X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Flb%2Fnode.c;h=b5e9da71376c7472d005d41e4c9d05b96826d3c5;hb=c7cceeebb738b0fabd93d2c4fdfd561321a2be1d;hp=e19964d2f1c2bfc9d5cff83d59752cd458249dbe;hpb=d92a0b553fd2872b4fcda25994aaa8852d254824;p=vpp.git diff --git a/src/plugins/lb/node.c b/src/plugins/lb/node.c index e19964d2f1c..b5e9da71376 100644 --- a/src/plugins/lb/node.c +++ b/src/plugins/lb/node.c @@ -173,14 +173,27 @@ lb_node_get_other_ports6 (ip6_header_t *ip60) return 0; } -static_always_inline u32 -lb_node_get_hash (vlib_buffer_t *p, u8 is_input_v4) +static_always_inline void +lb_node_get_hash (lb_main_t *lbm, vlib_buffer_t *p, u8 is_input_v4, + u32 *hash, u32 *vip_idx, u8 per_port_vip) { - u32 hash; + vip_port_key_t key; + clib_bihash_kv_8_8_t kv, value; + + /* For vip case, retrieve vip index for ip lookup */ + *vip_idx = vnet_buffer (p)->ip.adj_index[VLIB_TX]; + + if (per_port_vip) + { + /* For per-port-vip case, ip lookup stores placeholder index */ + key.vip_prefix_index = *vip_idx; + } + if (is_input_v4) { ip4_header_t *ip40; u64 ports; + ip40 = vlib_buffer_get_current (p); if (PREDICT_TRUE( ip40->protocol == IP_PROTOCOL_TCP @@ -190,13 +203,20 @@ lb_node_get_hash (vlib_buffer_t *p, u8 is_input_v4) else ports = lb_node_get_other_ports4 (ip40); - hash = lb_hash_hash (*((u64 *) &ip40->address_pair), ports, 0, 0, 0); + *hash = lb_hash_hash (*((u64 *) &ip40->address_pair), ports, 0, 0, 0); + + if (per_port_vip) + { + key.protocol = ip40->protocol; + key.port = (u16)(ports & 0xFFFF); + } } else { ip6_header_t *ip60; ip60 = vlib_buffer_get_current (p); u64 ports; + if (PREDICT_TRUE( ip60->protocol == IP_PROTOCOL_TCP || ip60->protocol == IP_PROTOCOL_UDP)) @@ -205,22 +225,43 @@ lb_node_get_hash (vlib_buffer_t *p, u8 is_input_v4) else ports = lb_node_get_other_ports6 (ip60); - hash = lb_hash_hash (ip60->src_address.as_u64[0], + *hash = lb_hash_hash (ip60->src_address.as_u64[0], ip60->src_address.as_u64[1], ip60->dst_address.as_u64[0], ip60->dst_address.as_u64[1], ports); + + if (per_port_vip) + { + key.protocol = ip60->protocol; + key.port = (u16)(ports & 0xFFFF); + } + } + + /* For per-port-vip case, retrieve vip index for vip_port_filter table */ + if (per_port_vip) + { + kv.key = key.as_u64; + if (clib_bihash_search_8_8(&lbm->vip_index_per_port, &kv, &value) < 0) + { + /* return default vip */ + *vip_idx = 0; + return; + } + *vip_idx = value.value; } - return hash; } static_always_inline uword -lb_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, +lb_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, + vlib_frame_t * frame, u8 is_input_v4, //Compile-time parameter stating that is input is v4 (or v6) - lb_encap_type_t encap_type) //Compile-time parameter is GRE4/GRE6/L3DSR/NAT4/NAT6 + lb_encap_type_t encap_type, //Compile-time parameter is GRE4/GRE6/L3DSR/NAT4/NAT6 + u8 per_port_vip) //Compile-time parameter stating that is per_port_vip or not { lb_main_t *lbm = &lb_main; u32 n_left_from, *from, next_index, *to_next, n_left_to_next; - u32 thread_index = vlib_get_thread_index (); + u32 thread_index = vm->thread_index; u32 lb_time = lb_hash_time_now (vm); lb_hash_t *sticky_ht = lb_get_sticky_table (thread_index); @@ -229,8 +270,13 @@ lb_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, next_index = node->cached_next_index; u32 nexthash0 = 0; + u32 next_vip_idx0 = ~0; if (PREDICT_TRUE(n_left_from > 0)) - nexthash0 = lb_node_get_hash (vlib_get_buffer (vm, from[0]), is_input_v4); + { + vlib_buffer_t *p0 = vlib_get_buffer (vm, from[0]); + lb_node_get_hash (lbm, p0, is_input_v4, &nexthash0, + &next_vip_idx0, per_port_vip); + } while (n_left_from > 0) { @@ -240,17 +286,21 @@ lb_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, u32 pi0; vlib_buffer_t *p0; lb_vip_t *vip0; - u32 asindex0; + u32 asindex0 = 0; u16 len0; u32 available_index0; u8 counter = 0; u32 hash0 = nexthash0; + u32 vip_index0 = next_vip_idx0; + u32 next0; if (PREDICT_TRUE(n_left_from > 1)) { vlib_buffer_t *p1 = vlib_get_buffer (vm, from[1]); //Compute next hash and prefetch bucket - nexthash0 = lb_node_get_hash (p1, is_input_v4); + lb_node_get_hash (lbm, p1, is_input_v4, + &nexthash0, &next_vip_idx0, + per_port_vip); lb_hash_prefetch_bucket (sticky_ht, nexthash0); //Prefetch for encap, next CLIB_PREFETCH(vlib_buffer_get_current (p1) - 64, 64, STORE); @@ -272,8 +322,8 @@ lb_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, n_left_to_next -= 1; p0 = vlib_get_buffer (vm, pi0); - vip0 = pool_elt_at_index(lbm->vips, - vnet_buffer (p0)->ip.adj_index[VLIB_TX]); + + vip0 = pool_elt_at_index(lbm->vips, vip_index0); if (is_input_v4) { @@ -290,10 +340,10 @@ lb_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, } lb_hash_get (sticky_ht, hash0, - vnet_buffer (p0)->ip.adj_index[VLIB_TX], lb_time, + vip_index0, lb_time, &available_index0, &asindex0); - if (PREDICT_TRUE(asindex0 != ~0)) + if (PREDICT_TRUE(asindex0 != 0)) { //Found an existing entry counter = LB_VIP_COUNTER_NEXT_PACKET; @@ -320,7 +370,7 @@ lb_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, //Note that when there is no AS configured, an entry is configured anyway. //But no configured AS is not something that should happen lb_hash_put (sticky_ht, hash0, asindex0, - vnet_buffer (p0)->ip.adj_index[VLIB_TX], + vip_index0, available_index0, lb_time); } else @@ -333,7 +383,7 @@ lb_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, vlib_increment_simple_counter ( &lbm->vip_counters[counter], thread_index, - vnet_buffer (p0)->ip.adj_index[VLIB_TX], + vip_index0, 1); //Now let's encap @@ -385,30 +435,43 @@ lb_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, else if (encap_type == LB_ENCAP_TYPE_L3DSR) /* encap L3DSR*/ { ip4_header_t *ip40; - tcp_header_t *th0; ip_csum_t csum; - u32 old_dst; - u32 old_dscp; + u32 old_dst, new_dst; + u8 old_tos, new_tos; ip40 = vlib_buffer_get_current (p0); old_dst = ip40->dst_address.as_u32; - old_dscp = ip40->tos; - ip40->dst_address = lbm->ass[asindex0].address.ip4; + new_dst = lbm->ass[asindex0].address.ip4.as_u32; + ip40->dst_address.as_u32 = lbm->ass[asindex0].address.ip4.as_u32; /* Get and rewrite DSCP bit */ + old_tos = ip40->tos; + new_tos = (u8) ((vip0->encap_args.dscp & 0x3F) << 2); ip40->tos = (u8) ((vip0->encap_args.dscp & 0x3F) << 2); csum = ip40->checksum; - csum = ip_csum_sub_even (csum, old_dst); - csum = ip_csum_sub_even (csum, old_dscp); - csum = ip_csum_add_even (csum, - lbm->ass[asindex0].address.ip4.as_u32); - csum = ip_csum_add_even (csum, ip40->tos); + csum = ip_csum_update (csum, old_tos, new_tos, + ip4_header_t, + tos /* changed member */); + csum = ip_csum_update (csum, old_dst, new_dst, + ip4_header_t, + dst_address /* changed member */); ip40->checksum = ip_csum_fold (csum); /* Recomputing L4 checksum after dst-IP modifying */ - th0 = ip4_next_header (ip40); - th0->checksum = 0; - th0->checksum = ip4_tcp_udp_compute_checksum (vm, p0, ip40); + if (ip40->protocol == IP_PROTOCOL_TCP) + { + tcp_header_t *th0; + th0 = ip4_next_header (ip40); + th0->checksum = 0; + th0->checksum = ip4_tcp_udp_compute_checksum (vm, p0, ip40); + } + else if (ip40->protocol == IP_PROTOCOL_UDP) + { + udp_header_t *uh0; + uh0 = ip4_next_header (ip40); + uh0->checksum = 0; + uh0->checksum = ip4_tcp_udp_compute_checksum (vm, p0, ip40); + } } else if ((encap_type == LB_ENCAP_TYPE_NAT4) || (encap_type == LB_ENCAP_TYPE_NAT6)) @@ -433,8 +496,7 @@ lb_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, csum, lbm->ass[asindex0].address.ip4.as_u32); ip40->checksum = ip_csum_fold (csum); - if ((ip40->protocol == IP_PROTOCOL_UDP) - || (uh->dst_port == vip0->encap_args.port)) + if (ip40->protocol == IP_PROTOCOL_UDP) { uh->dst_port = vip0->encap_args.target_port; csum = uh->checksum; @@ -445,7 +507,7 @@ lb_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, } else { - next_index = LB_NEXT_DROP; + asindex0 = 0; } } else if ((is_input_v4 == 0) && (encap_type == LB_ENCAP_TYPE_NAT6)) @@ -478,25 +540,25 @@ lb_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, } else { - next_index = LB_NEXT_DROP; + asindex0 = 0; } } } + next0 = lbm->ass[asindex0].dpo.dpoi_next_node; + //Note that this is going to error if asindex0 == 0 + vnet_buffer (p0)->ip.adj_index[VLIB_TX] = + lbm->ass[asindex0].dpo.dpoi_index; if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED)) { lb_trace_t *tr = vlib_add_trace (vm, node, p0, sizeof(*tr)); tr->as_index = asindex0; - tr->vip_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX]; + tr->vip_index = vip_index0; } //Enqueue to next - //Note that this is going to error if asindex0 == 0 - vnet_buffer (p0)->ip.adj_index[VLIB_TX] = - lbm->ass[asindex0].dpo.dpoi_index; vlib_validate_buffer_enqueue_x1( - vm, node, next_index, to_next, n_left_to_next, pi0, - lbm->ass[asindex0].dpo.dpoi_next_node); + vm, node, next_index, to_next, n_left_to_next, pi0, next0); } vlib_put_next_frame (vm, node, next_index, n_left_to_next); } @@ -594,13 +656,14 @@ lb_nodeport_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, entry0 = hash_get_mem(lbm->vip_index_by_nodeport, &(udp_0->dst_port)); //Enqueue to next - vnet_buffer(p0)->ip.adj_index[VLIB_TX] = entry0[0]; + vnet_buffer(p0)->ip.adj_index[VLIB_TX] = entry0 ? entry0[0] + : ADJ_INDEX_INVALID; if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED)) { lb_nodeport_trace_t *tr = vlib_add_trace (vm, node, p0, sizeof(*tr)); - tr->vip_index = entry0[0]; + tr->vip_index = entry0 ? entry0[0] : ADJ_INDEX_INVALID; tr->node_port = (u32) clib_net_to_host_u16 (udp_0->dst_port); } @@ -884,49 +947,84 @@ static uword lb6_gre6_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE6); + return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE6, 0); } static uword lb6_gre4_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE4); + return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE4, 0); } static uword lb4_gre6_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE6); + return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE6, 0); } static uword lb4_gre4_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE4); + return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE4, 0); +} + +static uword +lb6_gre6_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE6, 1); +} + +static uword +lb6_gre4_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_GRE4, 1); +} + +static uword +lb4_gre6_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE6, 1); +} + +static uword +lb4_gre4_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_GRE4, 1); } static uword lb4_l3dsr_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame) + vlib_frame_t * frame) { - return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_L3DSR); + return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_L3DSR, 0); } static uword -lb6_nat6_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame) +lb4_l3dsr_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame) { - return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_NAT6); + return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_L3DSR, 1); } static uword -lb4_nat4_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame) +lb6_nat6_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return lb_node_fn (vm, node, frame, 0, LB_ENCAP_TYPE_NAT6, 1); +} + +static uword +lb4_nat4_port_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame) { - return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_NAT4); + return lb_node_fn (vm, node, frame, 1, LB_ENCAP_TYPE_NAT4, 1); } static uword @@ -949,7 +1047,8 @@ VLIB_REGISTER_NODE (lb6_gre6_node) = .name = "lb6-gre6", .vector_size = sizeof(u32), .format_trace = format_lb_trace, - .n_errors = LB_N_ERROR, .error_strings = lb_error_strings, + .n_errors = LB_N_ERROR, + .error_strings = lb_error_strings, .n_next_nodes = LB_N_NEXT, .next_nodes = { [LB_NEXT_DROP] = "error-drop" }, @@ -978,7 +1077,7 @@ VLIB_REGISTER_NODE (lb4_gre6_node) = .error_strings = lb_error_strings, .n_next_nodes = LB_N_NEXT, .next_nodes = - { [LB_NEXT_DROP] = "error-drop" }, + { [LB_NEXT_DROP] = "error-drop" }, }; VLIB_REGISTER_NODE (lb4_gre4_node) = @@ -989,7 +1088,72 @@ VLIB_REGISTER_NODE (lb4_gre4_node) = .format_trace = format_lb_trace, .n_errors = LB_N_ERROR, .error_strings = lb_error_strings, - .n_next_nodes = LB_N_NEXT, + .n_next_nodes = LB_N_NEXT, + .next_nodes = + { [LB_NEXT_DROP] = "error-drop" }, + }; + +VLIB_REGISTER_NODE (lb6_gre6_port_node) = + { + .function = lb6_gre6_port_node_fn, + .name = "lb6-gre6-port", + .vector_size = sizeof(u32), + .format_trace = format_lb_trace, + .n_errors = LB_N_ERROR, + .error_strings = lb_error_strings, + .n_next_nodes = LB_N_NEXT, + .next_nodes = + { [LB_NEXT_DROP] = "error-drop" }, + }; + +VLIB_REGISTER_NODE (lb6_gre4_port_node) = + { + .function = lb6_gre4_port_node_fn, + .name = "lb6-gre4-port", + .vector_size = sizeof(u32), + .format_trace = format_lb_trace, + .n_errors = LB_N_ERROR, + .error_strings = lb_error_strings, + .n_next_nodes = LB_N_NEXT, + .next_nodes = + { [LB_NEXT_DROP] = "error-drop" }, + }; + +VLIB_REGISTER_NODE (lb4_gre6_port_node) = + { + .function = lb4_gre6_port_node_fn, + .name = "lb4-gre6-port", + .vector_size = sizeof(u32), + .format_trace = format_lb_trace, + .n_errors = LB_N_ERROR, + .error_strings = lb_error_strings, + .n_next_nodes = LB_N_NEXT, + .next_nodes = + { [LB_NEXT_DROP] = "error-drop" }, + }; + +VLIB_REGISTER_NODE (lb4_gre4_port_node) = + { + .function = lb4_gre4_port_node_fn, + .name = "lb4-gre4-port", + .vector_size = sizeof(u32), + .format_trace = format_lb_trace, + .n_errors = LB_N_ERROR, + .error_strings = lb_error_strings, + .n_next_nodes = LB_N_NEXT, + .next_nodes = + { [LB_NEXT_DROP] = "error-drop" }, + }; + +VLIB_REGISTER_NODE (lb4_l3dsr_port_node) = + { + .function = lb4_l3dsr_port_node_fn, + .name = "lb4-l3dsr-port", + .vector_size = sizeof(u32), + .format_trace = format_lb_trace, + .n_errors = LB_N_ERROR, + .error_strings = lb_error_strings, + .n_next_nodes = LB_N_NEXT, .next_nodes = { [LB_NEXT_DROP] = "error-drop" }, }; @@ -1007,10 +1171,10 @@ VLIB_REGISTER_NODE (lb4_l3dsr_node) = { [LB_NEXT_DROP] = "error-drop" }, }; -VLIB_REGISTER_NODE (lb6_nat6_node) = +VLIB_REGISTER_NODE (lb6_nat6_port_node) = { - .function = lb6_nat6_node_fn, - .name = "lb6-nat6", + .function = lb6_nat6_port_node_fn, + .name = "lb6-nat6-port", .vector_size = sizeof(u32), .format_trace = format_lb_trace, .n_errors = LB_N_ERROR, @@ -1020,10 +1184,10 @@ VLIB_REGISTER_NODE (lb6_nat6_node) = { [LB_NEXT_DROP] = "error-drop" }, }; -VLIB_REGISTER_NODE (lb4_nat4_node) = +VLIB_REGISTER_NODE (lb4_nat4_port_node) = { - .function = lb4_nat4_node_fn, - .name = "lb4-nat4", + .function = lb4_nat4_port_node_fn, + .name = "lb4-nat4-port", .vector_size = sizeof(u32), .format_trace = format_lb_trace, .n_errors = LB_N_ERROR, @@ -1058,7 +1222,7 @@ VLIB_REGISTER_NODE (lb4_nodeport_node) = .n_next_nodes = LB4_NODEPORT_N_NEXT, .next_nodes = { - [LB4_NODEPORT_NEXT_IP4_NAT4] = "lb4-nat4", + [LB4_NODEPORT_NEXT_IP4_NAT4] = "lb4-nat4-port", [LB4_NODEPORT_NEXT_DROP] = "error-drop", }, }; @@ -1074,7 +1238,7 @@ VLIB_REGISTER_NODE (lb6_nodeport_node) = .n_next_nodes = LB6_NODEPORT_N_NEXT, .next_nodes = { - [LB6_NODEPORT_NEXT_IP6_NAT6] = "lb6-nat6", + [LB6_NODEPORT_NEXT_IP6_NAT6] = "lb6-nat6-port", [LB6_NODEPORT_NEXT_DROP] = "error-drop", }, }; @@ -1124,4 +1288,3 @@ VLIB_REGISTER_NODE (lb_nat6_in2out_node) = [LB_NAT6_IN2OUT_NEXT_LOOKUP] = "ip6-lookup", }, }; -