From 6af1c04f925f0d74fc02789cf8227706ed6a8c2a Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Fri, 26 May 2017 03:48:53 -0700 Subject: MPLS lookup DPO does not pop the label (nor does it handle replicate) Change-Id: I7de6b96631d1645d0eadd38525860d84d78e316d Signed-off-by: Neale Ranns --- src/vnet/dpo/lookup_dpo.c | 47 +++++++++++++++++--- src/vnet/ip/ip4_forward.c | 1 - src/vnet/mpls/mpls_lookup.c | 79 +--------------------------------- src/vnet/mpls/mpls_lookup.h | 102 ++++++++++++++++++++++++++++++++++++++++++++ test/test_mpls.py | 20 +++++++++ 5 files changed, 165 insertions(+), 84 deletions(-) create mode 100644 src/vnet/mpls/mpls_lookup.h diff --git a/src/vnet/dpo/lookup_dpo.c b/src/vnet/dpo/lookup_dpo.c index cf489d7eb35..26363a2f0fa 100644 --- a/src/vnet/dpo/lookup_dpo.c +++ b/src/vnet/dpo/lookup_dpo.c @@ -15,8 +15,8 @@ #include #include -#include -#include +#include +#include #include #include #include @@ -999,7 +999,7 @@ lookup_dpo_mpls_inline (vlib_main_t * vm, while (n_left_from > 0 && n_left_to_next > 0) { - u32 bi0, lkdi0, lbi0, fib_index0, next0; + u32 bi0, lkdi0, lbi0, fib_index0, next0, hash0; const mpls_unicast_header_t * hdr0; const load_balance_t *lb0; const lookup_dpo_t * lkd0; @@ -1043,9 +1043,44 @@ lookup_dpo_mpls_inline (vlib_main_t * vm, next0 = dpo0->dpoi_next_node; vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; - vlib_increment_combined_counter - (cm, thread_index, lbi0, 1, - vlib_buffer_length_in_chain (vm, b0)); + + if (MPLS_IS_REPLICATE & lbi0) + { + next0 = mpls_lookup_to_replicate_edge; + vnet_buffer (b0)->ip.adj_index[VLIB_TX] = + (lbi0 & ~MPLS_IS_REPLICATE); + } + else + { + lb0 = load_balance_get(lbi0); + ASSERT (lb0->lb_n_buckets > 0); + ASSERT (is_pow2 (lb0->lb_n_buckets)); + + if (PREDICT_FALSE(lb0->lb_n_buckets > 1)) + { + hash0 = vnet_buffer (b0)->ip.flow_hash = + mpls_compute_flow_hash(hdr0, lb0->lb_hash_config); + dpo0 = load_balance_get_fwd_bucket + (lb0, + (hash0 & (lb0->lb_n_buckets_minus_1))); + } + else + { + dpo0 = load_balance_get_bucket_i (lb0, 0); + } + next0 = dpo0->dpoi_next_node; + + vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; + + vlib_increment_combined_counter + (cm, thread_index, lbi0, 1, + vlib_buffer_length_in_chain (vm, b0)); + } + + vnet_buffer (b0)->mpls.ttl = ((char*)hdr0)[3]; + vnet_buffer (b0)->mpls.exp = (((char*)hdr0)[2] & 0xe) >> 1; + vnet_buffer (b0)->mpls.first = 1; + vlib_buffer_advance(b0, sizeof(*hdr0)); if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) { diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c index 374671827a9..d86f22ca984 100755 --- a/src/vnet/ip/ip4_forward.c +++ b/src/vnet/ip/ip4_forward.c @@ -2473,7 +2473,6 @@ ip4_rewrite_inline (vlib_main_t * vm, } /* Verify checksum. */ - ASSERT (ip0->checksum == ip4_header_checksum (ip0)); ASSERT (ip1->checksum == ip4_header_checksum (ip1)); } else diff --git a/src/vnet/mpls/mpls_lookup.c b/src/vnet/mpls/mpls_lookup.c index 42e5399c2da..7cedc3846bf 100644 --- a/src/vnet/mpls/mpls_lookup.c +++ b/src/vnet/mpls/mpls_lookup.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include @@ -30,7 +30,7 @@ static vlib_node_registration_t mpls_lookup_node; /** * The arc/edge from the MPLS lookup node to the MPLS replicate node */ -static u32 mpls_lookup_to_replicate_edge; +u32 mpls_lookup_to_replicate_edge; typedef struct { u32 next_index; @@ -56,81 +56,6 @@ format_mpls_lookup_trace (u8 * s, va_list * args) return s; } -/* - * Compute flow hash. - * We'll use it to select which adjacency to use for this flow. And other things. - */ -always_inline u32 -mpls_compute_flow_hash (const mpls_unicast_header_t * hdr, - flow_hash_config_t flow_hash_config) -{ - /* - * We need to byte swap so we use the numerical value. i.e. an odd label - * leads to an odd bucket. as opposed to a label above and below value X. - */ - u8 next_label_is_entropy; - mpls_label_t ho_label; - u32 hash, value; - - ho_label = clib_net_to_host_u32(hdr->label_exp_s_ttl); - hash = vnet_mpls_uc_get_label(ho_label); - next_label_is_entropy = 0; - - while (MPLS_EOS != vnet_mpls_uc_get_s(ho_label)) - { - hdr++; - ho_label = clib_net_to_host_u32(hdr->label_exp_s_ttl); - value = vnet_mpls_uc_get_label(ho_label); - - if (1 == next_label_is_entropy) - { - /* - * The label is an entropy value, use it alone as the hash - */ - return (ho_label); - } - if (MPLS_IETF_ENTROPY_LABEL == value) - { - /* - * we've met a label in the stack indicating that tha next - * label is an entropy value - */ - next_label_is_entropy = 1; - } - else - { - /* - * XOR the label values in the stack together to - * build up the hash value - */ - hash ^= value; - } - } - - /* - * check the top nibble for v4 and v6 - */ - hdr++; - - switch (((u8*)hdr)[0] >> 4) - { - case 4: - /* incorporate the v4 flow-hash */ - hash ^= ip4_compute_flow_hash ((const ip4_header_t *)hdr, - IP_FLOW_HASH_DEFAULT); - break; - case 6: - /* incorporate the v6 flow-hash */ - hash ^= ip6_compute_flow_hash ((const ip6_header_t *)hdr, - IP_FLOW_HASH_DEFAULT); - break; - default: - break; - } - - return (hash); -} - static inline uword mpls_lookup (vlib_main_t * vm, vlib_node_runtime_t * node, diff --git a/src/vnet/mpls/mpls_lookup.h b/src/vnet/mpls/mpls_lookup.h new file mode 100644 index 00000000000..28c9124f9bf --- /dev/null +++ b/src/vnet/mpls/mpls_lookup.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MPLS_LOOKUP_H__ +#define __MPLS_LOOKUP_H__ + +#include +#include + +/** + * The arc/edge from the MPLS lookup node to the MPLS replicate node + */ +u32 mpls_lookup_to_replicate_edge; + +/* + * Compute flow hash. + * We'll use it to select which adjacency to use for this flow. And other things. + */ +always_inline u32 +mpls_compute_flow_hash (const mpls_unicast_header_t * hdr, + flow_hash_config_t flow_hash_config) +{ + /* + * We need to byte swap so we use the numerical value. i.e. an odd label + * leads to an odd bucket. as opposed to a label above and below value X. + */ + u8 next_label_is_entropy; + mpls_label_t ho_label; + u32 hash, value; + + ho_label = clib_net_to_host_u32(hdr->label_exp_s_ttl); + hash = vnet_mpls_uc_get_label(ho_label); + next_label_is_entropy = 0; + + while (MPLS_EOS != vnet_mpls_uc_get_s(ho_label)) + { + hdr++; + ho_label = clib_net_to_host_u32(hdr->label_exp_s_ttl); + value = vnet_mpls_uc_get_label(ho_label); + + if (1 == next_label_is_entropy) + { + /* + * The label is an entropy value, use it alone as the hash + */ + return (ho_label); + } + if (MPLS_IETF_ENTROPY_LABEL == value) + { + /* + * we've met a label in the stack indicating that tha next + * label is an entropy value + */ + next_label_is_entropy = 1; + } + else + { + /* + * XOR the label values in the stack together to + * build up the hash value + */ + hash ^= value; + } + } + + /* + * check the top nibble for v4 and v6 + */ + hdr++; + + switch (((u8*)hdr)[0] >> 4) + { + case 4: + /* incorporate the v4 flow-hash */ + hash ^= ip4_compute_flow_hash ((const ip4_header_t *)hdr, + IP_FLOW_HASH_DEFAULT); + break; + case 6: + /* incorporate the v6 flow-hash */ + hash ^= ip6_compute_flow_hash ((const ip6_header_t *)hdr, + IP_FLOW_HASH_DEFAULT); + break; + default: + break; + } + + return (hash); +} + +#endif /* __MPLS_LOOKUP_H__ */ diff --git a/test/test_mpls.py b/test/test_mpls.py index 77cec429f5a..e3d013af4d6 100644 --- a/test/test_mpls.py +++ b/test/test_mpls.py @@ -771,6 +771,26 @@ class TestMPLS(VppTestCase): rx = self.pg1.get_capture(packet_count) self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1) + # + # Double pop + # + route_36_neos = VppMplsRoute(self, 36, 0, + [VppRoutePath("0.0.0.0", + 0xffffffff)]) + route_36_neos.add_vpp_config() + + self.vapi.cli("clear trace") + tx = self.create_stream_labelled_ip4(self.pg0, [36, 35], + ping=1, ip_itf=self.pg1) + self.pg0.add_stream(tx) + + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg1.get_capture(len(tx)) + self.verify_capture_ip4(self.pg1, rx, tx, ping_resp=1) + + route_36_neos.remove_vpp_config() route_35_eos.remove_vpp_config() route_34_eos.remove_vpp_config() -- cgit 1.2.3-korg