On Fri, Feb 15, 2013 at 08:58:52AM -0800, Ben Pfaff wrote: > On Fri, Feb 15, 2013 at 06:55:55PM +0900, Simon Horman wrote: > > When encoding MPLS information in ODP flow key data use encap() > > for encap for frames. This seems to be in keeping with datapath/README. > > > > before: eth(...), eth_type(0x8847), mpls(...), encap(ip(...), tcp(...)) > > after: eth(...), eth_type(0x8847), mpls(...), ip(...), tcp(...) > > I think you got the before and after backward.
Thanks, I have fixed that below. > We also need to update odp_flow_key_from_flow(). Thanks, I had that in the next patch in the series. A combined patch with a revised commit message is below. From: Simon Horman <ho...@verge.net.au> odp: Use encap() for MPLS-encapsulated ODP flow key data This patch has two components: 1. odp_flow_key_from_flow() is updated to extract encapsulated frame information from MPLS flows. It does this by encoding the encapsualted frame in an encap() in the resulting ODP key data. A subsequent patch will introduce code to set flow->encap_dl_type which will activate this change. 2. Update parse_l2_5_onward() to read an MPLS-encapsulated frame from inside encap() in ODP key data. This consumes ODP key data produced by odp_flow_key_from_flow(). before: eth(...), eth_type(0x8847), mpls(...), ip(...), tcp(...) after: eth(...), eth_type(0x8847), mpls(...), encap(ip(...), tcp(...)) The use of encap() for MPLS-encapsulated frames was suggested by Ben Pfaff and seems to be in keeping with datapath/README. Signed-off-by: Simon Horman <ho...@verge.net.au> --- v2.20 (draft) * Squash "Update parse_l2_5_onward to use encap for MPLS" and "odp_flow_key_from_flow: Allow of encapsulated frames" and rename the result "odp: Use encap() for MPLS-encapsulated ODP flow key data". v2.19 * As suggested by Ben Pfaff - Remove encap_dl_type parameter from odp_flow_key_from_flow() - Use encap for mpls in ODP flow key data. before: eth(...), eth_type(0x8847), mpls(...), ip(...), tcp(...) after: eth(...), eth_type(0x8847), mpls(...), encap(ip(...), tcp(...)) * Coding style fix for actions_allow_l3_extraction(). Use {} in conjunction with if statements. * Enhance actions_allow_l3_extraction to return when the first MPLS_PUSH action with a non-MPLS ether type is found rather than when the first MPLS_PUSH action is found. * Remove actions_allow_l3_extraction() and obtain encap_dl_type from xlate_actions() instead. * Removed non-odp_flow_key_from_flow portions. These are now present in ofproto: Allow richer matches based on actions(). * Rename patch from "actions: Allow secondary decoding of a flow" to "actions: odp_flow_key_from_flow: Allow of encapsulated frames" v2.18 * Update odp_flow_key_from_flow() to use dl_type_is_ip_any() wrapper. As odp_flow_key_from_flow() is paramatised over encap_dl_type this seems to be a good approach. v2.17 * Rebase 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/odp-util.c | 85 ++++++++++++++++++++++++++++++++----------------- tests/ofproto-dpif.at | 4 +-- 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/lib/odp-util.c b/lib/odp-util.c index f3f66b7..a6002db 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -1506,7 +1506,8 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow, uint32_t odp_in_port) { struct ovs_key_ethernet *eth_key; - size_t encap; + size_t encap_vlan = 0, encap_mpls = 0; + ovs_be16 dl_type = flow_innermost_dl_type(flow); if (flow->skb_priority) { nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, flow->skb_priority); @@ -1534,12 +1535,10 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow, if (flow->vlan_tci != htons(0) || flow->dl_type == htons(ETH_TYPE_VLAN)) { nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, htons(ETH_TYPE_VLAN)); nl_msg_put_be16(buf, OVS_KEY_ATTR_VLAN, flow->vlan_tci); - encap = nl_msg_start_nested(buf, OVS_KEY_ATTR_ENCAP); + encap_vlan = nl_msg_start_nested(buf, OVS_KEY_ATTR_ENCAP); if (flow->vlan_tci == htons(0)) { goto unencap; } - } else { - encap = 0; } if (ntohs(flow->dl_type) < ETH_TYPE_MIN) { @@ -1548,7 +1547,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)) { + 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_lse = flow->mpls_lse; + if (flow->encap_dl_type) { + encap_mpls = nl_msg_start_nested(buf, OVS_KEY_ATTR_ENCAP); + } + } + + 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, @@ -1559,7 +1569,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, @@ -1571,8 +1581,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, @@ -1585,15 +1595,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_lse = flow->mpls_lse; - } - - if (is_ip_any(flow) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) { + if (dl_type_is_ip_any(dl_type) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) { if (flow->nw_proto == IPPROTO_TCP) { struct ovs_key_tcp *tcp_key; @@ -1608,7 +1610,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; @@ -1616,7 +1618,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; @@ -1640,8 +1642,11 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow, } unencap: - if (encap) { - nl_msg_end_nested(buf, encap); + if (encap_mpls) { + nl_msg_end_nested(buf, encap_mpls); + } + if (encap_vlan) { + nl_msg_end_nested(buf, encap_vlan); } } @@ -1801,10 +1806,14 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], const struct nlattr *key, size_t key_len) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + enum odp_key_fitness fitness, mpls_fitness = 0; ovs_be16 dl_type; /* Parse MPLS label stack entry */ if (eth_type_mpls(flow->dl_type)) { + const struct nlattr *encap + = (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ENCAP) + ? attrs[OVS_KEY_ATTR_ENCAP] : NULL); /* Calculate fitness of outer attributes. */ expected_attrs |= (UINT64_C(1) << OVS_KEY_ATTR_MPLS); @@ -1815,12 +1824,27 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], flow->mpls_lse = nl_attr_get_be32(attrs[OVS_KEY_ATTR_MPLS]); flow->mpls_depth++; - if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV4)) { - flow->encap_dl_type = htons(ETH_TYPE_IP); - } else if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV6)) { - flow->encap_dl_type = htons(ETH_TYPE_IPV6); - } else if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ARP)) { - flow->encap_dl_type = htons(ETH_TYPE_ARP); + /* Encap may not be present if nothing is known about the + * encapsulated frame */ + if (encap) { + expected_attrs |= (UINT64_C(1) << OVS_KEY_ATTR_ENCAP); + mpls_fitness = check_expectations(present_attrs, out_of_range_attr, + expected_attrs, key, key_len); + + /* Now parse the encapsulated attributes. */ + if (!parse_flow_nlattrs(nl_attr_get(encap), nl_attr_get_size(encap), + attrs, &present_attrs, &out_of_range_attr)) { + return ODP_FIT_ERROR; + } + expected_attrs = 0; + + if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV4)) { + flow->encap_dl_type = htons(ETH_TYPE_IP); + } else if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV6)) { + flow->encap_dl_type = htons(ETH_TYPE_IPV6); + } else if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ARP)) { + flow->encap_dl_type = htons(ETH_TYPE_ARP); + } } } @@ -1939,8 +1963,11 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], } } - return check_expectations(present_attrs, out_of_range_attr, expected_attrs, - key, key_len); + fitness = check_expectations(present_attrs, out_of_range_attr, + expected_attrs, key, key_len); + + /* The overall fitness is the worse of the outer and inner attributes. */ + return MAX(fitness, mpls_fitness); } /* Parse 802.1Q header then encapsulated L3 attributes. */ diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 8f11b82..15069bd 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -359,7 +359,7 @@ dnl Modified MPLS actions. AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log]) for i in 1 2 3; do - ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:55:55:55:55:55,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=100,tc=7,ttl=64,bos=1),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)' + ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:55:55:55:55:55,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=100,tc=7,ttl=64,bos=1),encap(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))' done OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) @@ -398,7 +398,7 @@ dnl Modified MPLS pop action. AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log]) for i in 1 2 3; do - ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=60:66:66:66:66:66,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=10,tc=3,ttl=100,bos=1),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)' + ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=60:66:66:66:66:66,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=10,tc=3,ttl=100,bos=1),encap(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))' done OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit]) -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev