X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=vnet%2Fvnet%2Flisp-gpe%2Flisp_gpe.c;h=0eacb385c58fb80e82b9b1c7c3fcc529018c201f;hb=324112fad06e0461958f22827f944595466e1891;hp=fd1e1a4608e9e7c2d3b28ea4dd778b6002ee13e6;hpb=577c3553dd6939e998c78c5a389750aac3a67f8b;p=vpp.git diff --git a/vnet/vnet/lisp-gpe/lisp_gpe.c b/vnet/vnet/lisp-gpe/lisp_gpe.c index fd1e1a4608e..0eacb385c58 100644 --- a/vnet/vnet/lisp-gpe/lisp_gpe.c +++ b/vnet/vnet/lisp-gpe/lisp_gpe.c @@ -17,585 +17,69 @@ lisp_gpe_main_t lisp_gpe_main; -/* avoids calling route callbacks for src fib */ -static void -ip4_sd_fib_set_adj_index (lisp_gpe_main_t * lgm, ip4_fib_t * fib, u32 flags, - u32 dst_address_u32, u32 dst_address_length, - u32 adj_index) -{ - ip_lookup_main_t * lm = lgm->lookup_main; - uword * hash; - - if (vec_bytes(fib->old_hash_values)) - memset (fib->old_hash_values, ~0, vec_bytes (fib->old_hash_values)); - if (vec_bytes(fib->new_hash_values)) - memset (fib->new_hash_values, ~0, vec_bytes (fib->new_hash_values)); - fib->new_hash_values[0] = adj_index; - - /* Make sure adj index is valid. */ - if (CLIB_DEBUG > 0) - (void) ip_get_adjacency (lm, adj_index); - - hash = fib->adj_index_by_dst_address[dst_address_length]; - - hash = _hash_set3 (hash, dst_address_u32, - fib->new_hash_values, - fib->old_hash_values); - - fib->adj_index_by_dst_address[dst_address_length] = hash; -} - -/* copied from ip4_forward since it's static */ -static void -ip4_fib_init_adj_index_by_dst_address (ip_lookup_main_t * lm, - ip4_fib_t * fib, - u32 address_length) -{ - hash_t * h; - uword max_index; - - ASSERT (lm->fib_result_n_bytes >= sizeof (uword)); - lm->fib_result_n_words = round_pow2 (lm->fib_result_n_bytes, sizeof (uword)) / sizeof (uword); - - fib->adj_index_by_dst_address[address_length] = - hash_create (32 /* elts */, lm->fib_result_n_words * sizeof (uword)); - - hash_set_flags (fib->adj_index_by_dst_address[address_length], - HASH_FLAG_NO_AUTO_SHRINK); - - h = hash_header (fib->adj_index_by_dst_address[address_length]); - max_index = (hash_value_bytes (h) / sizeof (fib->new_hash_values[0])) - 1; - - /* Initialize new/old hash value vectors. */ - vec_validate_init_empty (fib->new_hash_values, max_index, ~0); - vec_validate_init_empty (fib->old_hash_values, max_index, ~0); -} - -void -ip4_sd_fib_add_del_src_route (lisp_gpe_main_t * lgm, - ip4_add_del_route_args_t * a) +static int +lisp_gpe_rewrite (lisp_gpe_tunnel_t * t) { - ip_lookup_main_t * lm = lgm->lookup_main; - ip4_fib_t * fib; - u32 dst_address, dst_address_length, adj_index, old_adj_index; - uword * hash, is_del; - - /* Either create new adjacency or use given one depending on arguments. */ - if (a->n_add_adj > 0) - ip_add_adjacency (lm, a->add_adj, a->n_add_adj, &adj_index); - else - adj_index = a->adj_index; - - dst_address = a->dst_address.data_u32; - dst_address_length = a->dst_address_length; - - fib = pool_elt_at_index(lgm->src_fibs, a->table_index_or_table_id); - - if (! fib->adj_index_by_dst_address[dst_address_length]) - ip4_fib_init_adj_index_by_dst_address (lm, fib, dst_address_length); - - hash = fib->adj_index_by_dst_address[dst_address_length]; - - is_del = (a->flags & IP4_ROUTE_FLAG_DEL) != 0; + u8 *rw = 0; + lisp_gpe_header_t * lisp0; + int len; - if (is_del) + if (ip_addr_version(&t->src) == IP4) { - fib->old_hash_values[0] = ~0; - hash = _hash_unset (hash, dst_address, fib->old_hash_values); - fib->adj_index_by_dst_address[dst_address_length] = hash; - } - else - ip4_sd_fib_set_adj_index (lgm, fib, a->flags, dst_address, - dst_address_length, adj_index); - - old_adj_index = fib->old_hash_values[0]; - - ip4_fib_mtrie_add_del_route (fib, a->dst_address, dst_address_length, - is_del ? old_adj_index : adj_index, - is_del); - - /* Delete old adjacency index if present and changed. */ - if (! (a->flags & IP4_ROUTE_FLAG_KEEP_OLD_ADJACENCY) - && old_adj_index != ~0 - && old_adj_index != adj_index) - ip_del_adjacency (lm, old_adj_index); -} - -void * -ip4_sd_get_src_route (lisp_gpe_main_t * lgm, u32 src_fib_index, - ip4_address_t * src, u32 address_length) -{ - ip4_fib_t * fib = pool_elt_at_index (lgm->src_fibs, src_fib_index); - uword * hash, * p; - - hash = fib->adj_index_by_dst_address[address_length]; - p = hash_get (hash, src->as_u32); - return (void *) p; -} - -typedef CLIB_PACKED (struct { - ip4_address_t address; - u32 address_length : 6; - u32 index : 26; -}) ip4_route_t; - -static void -ip4_sd_fib_clear_src_fib (lisp_gpe_main_t * lgm, ip4_fib_t * fib) -{ - ip4_route_t * routes = 0, * r; - u32 i; - - vec_reset_length (routes); - - for (i = 0; i < ARRAY_LEN (fib->adj_index_by_dst_address); i++) { - uword * hash = fib->adj_index_by_dst_address[i]; - hash_pair_t * p; - ip4_route_t x; - - x.address_length = i; + ip4_header_t * ip0; + ip4_udp_lisp_gpe_header_t * h0; + len = sizeof(*h0); - hash_foreach_pair (p, hash, - ({ - x.address.data_u32 = p->key; - vec_add1 (routes, x); - })); - } + vec_validate_aligned(rw, len - 1, CLIB_CACHE_LINE_BYTES); - vec_foreach (r, routes) { - ip4_add_del_route_args_t a; + h0 = (ip4_udp_lisp_gpe_header_t *) rw; - memset (&a, 0, sizeof (a)); - a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL; - a.table_index_or_table_id = fib - lgm->src_fibs; - a.dst_address = r->address; - a.dst_address_length = r->address_length; - a.adj_index = ~0; + /* Fixed portion of the (outer) ip4 header */ + ip0 = &h0->ip4; + ip0->ip_version_and_header_length = 0x45; + ip0->ttl = 254; + ip0->protocol = IP_PROTOCOL_UDP; - ip4_sd_fib_add_del_src_route (lgm, &a); - } -} + /* we fix up the ip4 header length and checksum after-the-fact */ + ip_address_copy_addr(&ip0->src_address, &t->src); + ip_address_copy_addr(&ip0->dst_address, &t->dst); + ip0->checksum = ip4_header_checksum (ip0); -int -ip4_sd_fib_add_del_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix, - ip_prefix_t * src_prefix, u32 table_id, - ip_adjacency_t * add_adj, u8 is_add) -{ - uword * p; - ip4_add_del_route_args_t a; - ip_adjacency_t * dst_adjp, dst_adj; - ip4_address_t dst = ip_prefix_v4(dst_prefix), src; - u32 dst_address_length = ip_prefix_len(dst_prefix), src_address_length = 0; - ip4_fib_t * src_fib; + /* UDP header, randomize src port on something, maybe? */ + h0->udp.src_port = clib_host_to_net_u16 (4341); + h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_lisp_gpe); - if (src_prefix) - { - src = ip_prefix_v4(src_prefix); - src_address_length = ip_prefix_len(src_prefix); + /* LISP-gpe header */ + lisp0 = &h0->lisp; } else - memset(&src, 0, sizeof(src)); - - /* lookup dst adj */ - p = ip4_get_route (lgm->im4, table_id, 0, dst.as_u8, dst_address_length); - - if (is_add) { - /* insert dst prefix to ip4 fib, if it's not in yet */ - if (p == 0) - { - /* dst adj should point to lisp gpe lookup */ - dst_adj = add_adj[0]; - dst_adj.lookup_next_index = lgm->ip4_lookup_next_lgpe_ip4_lookup; - - memset(&a, 0, sizeof(a)); - a.flags = IP4_ROUTE_FLAG_TABLE_ID; - a.table_index_or_table_id = table_id; /* vrf */ - a.adj_index = ~0; - a.dst_address_length = dst_address_length; - a.dst_address = dst; - a.flags |= IP4_ROUTE_FLAG_ADD; - a.add_adj = &dst_adj; - a.n_add_adj = 1; - - ip4_add_del_route (lgm->im4, &a); - - /* lookup dst adj to obtain the adj index */ - p = ip4_get_route (lgm->im4, table_id, 0, dst.as_u8, - dst_address_length); - if (p == 0) - { - clib_warning("Failed to insert dst route for eid %U!", - format_ip4_address_and_length, dst.as_u8, - dst_address_length); - return -1; - } - - /* allocate and init src ip4 fib */ - pool_get(lgm->src_fibs, src_fib); - ip4_mtrie_init (&src_fib->mtrie); - - /* reuse rewrite header to store pointer to src fib */ - dst_adjp = ip_get_adjacency (lgm->lookup_main, p[0]); - dst_adjp->rewrite_header.sw_if_index = src_fib - lgm->src_fibs; - } - } - else - { - if (p == 0) - { - clib_warning("Trying to delete inexistent dst route for %U. Aborting", - format_ip4_address_and_length, dst.as_u8, - dst_address_length); - return -1; - } - } + ip6_header_t * ip0; + ip6_udp_lisp_gpe_header_t * h0; + len = sizeof(*h0); - dst_adjp = ip_get_adjacency (lgm->lookup_main, p[0]); - - /* add/del src prefix to src fib */ - memset(&a, 0, sizeof(a)); - a.flags = IP4_ROUTE_FLAG_TABLE_ID; - a.table_index_or_table_id = dst_adjp->rewrite_header.sw_if_index; - a.adj_index = ~0; - a.flags |= is_add ? IP4_ROUTE_FLAG_ADD : IP4_ROUTE_FLAG_DEL; - a.add_adj = add_adj; - a.n_add_adj = 1; - /* if src prefix is null, add 0/0 */ - a.dst_address_length = src_address_length; - a.dst_address = src; - ip4_sd_fib_add_del_src_route (lgm, &a); - - /* if a delete, check if there are elements left in the src fib */ - if (!is_add) - { - src_fib = pool_elt_at_index(lgm->src_fibs, - dst_adjp->rewrite_header.sw_if_index); - if (!src_fib) - return 0; + vec_validate_aligned(rw, len - 1, CLIB_CACHE_LINE_BYTES); - /* if there's nothing left, clear src fib .. */ - if (ARRAY_LEN(src_fib->adj_index_by_dst_address) == 0) - { - ip4_sd_fib_clear_src_fib (lgm, src_fib); - pool_put(lgm->src_fibs, src_fib); - } + h0 = (ip6_udp_lisp_gpe_header_t *) rw; - /* .. and remove dst route */ - memset(&a, 0, sizeof(a)); - a.flags = IP4_ROUTE_FLAG_TABLE_ID; - a.table_index_or_table_id = table_id; /* vrf */ - a.adj_index = ~0; - a.dst_address_length = dst_address_length; - a.dst_address = dst; - a.flags |= IP4_ROUTE_FLAG_DEL; + /* Fixed portion of the (outer) ip6 header */ + ip0 = &h0->ip6; + ip0->ip_version_traffic_class_and_flow_label = + clib_host_to_net_u32 (0x6 << 28); + ip0->hop_limit = 254; + ip0->protocol = IP_PROTOCOL_UDP; - ip4_add_del_route (lgm->im4, &a); - } + /* we fix up the ip6 header length after-the-fact */ + ip_address_copy_addr(&ip0->src_address, &t->src); + ip_address_copy_addr(&ip0->dst_address, &t->dst); - return 0; -} + /* UDP header, randomize src port on something, maybe? */ + h0->udp.src_port = clib_host_to_net_u16 (4341); + h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_lisp_gpe); -static void * -ip4_sd_fib_get_route (lisp_gpe_main_t * lgm, ip_prefix_t * dst_prefix, - ip_prefix_t * src_prefix, u32 table_id) -{ - uword * p; - ip4_address_t dst = ip_prefix_v4(dst_prefix), src; - u32 dst_address_length = ip_prefix_len(dst_prefix), src_address_length = 0; - ip_adjacency_t * dst_adj; - - if (src_prefix) - { - src = ip_prefix_v4(src_prefix); - src_address_length = ip_prefix_len(src_prefix); + /* LISP-gpe header */ + lisp0 = &h0->lisp; } - else - memset(&src, 0, sizeof(src)); - - /* lookup dst adj */ - p = ip4_get_route (lgm->im4, table_id, 0, dst.as_u8, dst_address_length); - if (p == 0) - return p; - - dst_adj = ip_get_adjacency (lgm->lookup_main, p[0]); - return ip4_sd_get_src_route (lgm, dst_adj->rewrite_header.sw_if_index, &src, - src_address_length); -} - -typedef enum -{ - LGPE_IP4_LOOKUP_NEXT_DROP, - LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP, - LGPE_IP4_LOOKUP_N_NEXT, -} lgpe_ip4_lookup_next_t; - -always_inline void -ip4_src_fib_lookup_one (lisp_gpe_main_t * lgm, u32 src_fib_index0, - ip4_address_t * addr0, u32 * src_adj_index0) -{ - ip4_fib_mtrie_leaf_t leaf0, leaf1; - ip4_fib_mtrie_t * mtrie0; - - mtrie0 = &vec_elt_at_index(lgm->src_fibs, src_fib_index0)->mtrie; - - leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT; - leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 0); - leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 1); - leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 2); - leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 3); - - /* Handle default route. */ - leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0); - src_adj_index0[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf0); -} - -always_inline void -ip4_src_fib_lookup_two (lisp_gpe_main_t * lgm, u32 src_fib_index0, - u32 src_fib_index1, ip4_address_t * addr0, - ip4_address_t * addr1, u32 * src_adj_index0, - u32 * src_adj_index1) -{ - ip4_fib_mtrie_leaf_t leaf0, leaf1; - ip4_fib_mtrie_t * mtrie0, * mtrie1; - - mtrie0 = &vec_elt_at_index(lgm->src_fibs, src_fib_index0)->mtrie; - mtrie1 = &vec_elt_at_index(lgm->src_fibs, src_fib_index1)->mtrie; - - leaf0 = leaf1 = IP4_FIB_MTRIE_LEAF_ROOT; - - leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 0); - leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 0); - - leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 1); - leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 1); - - leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 2); - leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 2); - - leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0, addr0, 3); - leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1, addr1, 3); - - /* Handle default route. */ - leaf0 = (leaf0 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie0->default_leaf : leaf0); - leaf1 = (leaf1 == IP4_FIB_MTRIE_LEAF_EMPTY ? mtrie1->default_leaf : leaf1); - src_adj_index0[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf0); - src_adj_index1[0] = ip4_fib_mtrie_leaf_get_adj_index (leaf1); -} - -always_inline uword -lgpe_ip4_lookup (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - u32 n_left_from, next_index, * from, * to_next; - lisp_gpe_main_t * lgm = &lisp_gpe_main; - - from = vlib_frame_vector_args (from_frame); - n_left_from = from_frame->n_vectors; - - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from >= 4 && n_left_to_next >= 2) - { - u32 bi0, bi1; - vlib_buffer_t * b0, * b1; - ip4_header_t * ip0, * ip1; - u32 dst_adj_index0, src_adj_index0, src_fib_index0, dst_adj_index1, - src_adj_index1, src_fib_index1; - ip_adjacency_t * dst_adj0, * src_adj0, * dst_adj1, * src_adj1; - u32 next0, next1; - - next0 = next1 = LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP; - - /* Prefetch next iteration. */ - { - vlib_buffer_t * p2, * p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - - CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD); - CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD); - } - - bi0 = from[0]; - bi1 = from[1]; - to_next[0] = bi0; - to_next[1] = bi1; - from += 2; - to_next += 2; - n_left_to_next -= 2; - n_left_from -= 2; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - - ip0 = vlib_buffer_get_current (b0); - ip1 = vlib_buffer_get_current (b1); - - /* dst lookup was done by ip4 lookup */ - dst_adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX]; - dst_adj_index1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX]; - - dst_adj0 = ip_get_adjacency (lgm->lookup_main, dst_adj_index0); - dst_adj1 = ip_get_adjacency (lgm->lookup_main, dst_adj_index1); - - src_fib_index0 = dst_adj0->rewrite_header.sw_if_index; - src_fib_index1 = dst_adj1->rewrite_header.sw_if_index; - - /* if default route not hit in ip4 lookup */ - if (PREDICT_TRUE(src_fib_index0 != (u32) ~0 - && src_fib_index1 != (u32) ~0)) - { - ip4_src_fib_lookup_two (lgm, src_fib_index0, src_fib_index1, - &ip0->src_address, &ip1->src_address, - &src_adj_index0, &src_adj_index1); - - vnet_buffer(b0)->ip.adj_index[VLIB_TX] = src_adj_index0; - vnet_buffer(b1)->ip.adj_index[VLIB_TX] = src_adj_index1; - - src_adj0 = ip_get_adjacency (lgm->lookup_main, src_adj_index0); - src_adj1 = ip_get_adjacency (lgm->lookup_main, src_adj_index1); - - next0 = src_adj0->lookup_next_index; - next1 = src_adj1->lookup_next_index; - - /* prepare buffer for lisp-gpe output node */ - vnet_buffer (b0)->sw_if_index[VLIB_TX] = - src_adj0->rewrite_header.sw_if_index; - vnet_buffer (b1)->sw_if_index[VLIB_TX] = - src_adj1->rewrite_header.sw_if_index; - } - else - { - if (src_fib_index0 != (u32) ~0) - { - ip4_src_fib_lookup_one (lgm, src_fib_index0, - &ip0->src_address, &src_adj_index0); - vnet_buffer(b0)->ip.adj_index[VLIB_TX] = src_adj_index0; - src_adj0 = ip_get_adjacency (lgm->lookup_main, - src_adj_index0); - next0 = src_adj0->lookup_next_index; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = src_adj_index0; - } - if (src_fib_index1 != (u32) ~0) - { - ip4_src_fib_lookup_one (lgm, src_fib_index1, - &ip1->src_address, &src_adj_index1); - vnet_buffer(b1)->ip.adj_index[VLIB_TX] = src_adj_index1; - src_adj1 = ip_get_adjacency (lgm->lookup_main, - src_adj_index1); - next1 = src_adj1->lookup_next_index; - vnet_buffer (b1)->sw_if_index[VLIB_TX] = src_adj_index1; - } - } - - vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, - n_left_to_next, bi0, bi1, next0, - next1); - } - - while (n_left_from > 0 && n_left_to_next > 0) - { - vlib_buffer_t * b0; - ip4_header_t * ip0; - u32 bi0, dst_adj_index0, src_adj_index0, src_fib_index0; - u32 next0 = LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP; - ip_adjacency_t * dst_adj0, * src_adj0; - - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - ip0 = vlib_buffer_get_current (b0); - - /* dst lookup was done by ip4 lookup */ - dst_adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX]; - dst_adj0 = ip_get_adjacency (lgm->lookup_main, dst_adj_index0); - src_fib_index0 = dst_adj0->rewrite_header.sw_if_index; - - /* default route hit in ip4 lookup, send to lisp control plane */ - if (src_fib_index0 == (u32) ~0) - goto done; - - /* src lookup we do here */ - ip4_src_fib_lookup_one (lgm, src_fib_index0, &ip0->src_address, - &src_adj_index0); - vnet_buffer(b0)->ip.adj_index[VLIB_TX] = src_adj_index0; - src_adj0 = ip_get_adjacency (lgm->lookup_main, src_adj_index0); - next0 = src_adj0->lookup_next_index; - - /* prepare packet for lisp-gpe output node */ - vnet_buffer (b0)->sw_if_index[VLIB_TX] = - src_adj0->rewrite_header.sw_if_index; - done: - vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, - n_left_to_next, bi0, next0); - } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - return from_frame->n_vectors; -} - - -VLIB_REGISTER_NODE (lgpe_ip4_lookup_node) = { - .function = lgpe_ip4_lookup, - .name = "lgpe-ip4-lookup", - .vector_size = sizeof (u32), - - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_next_nodes = LGPE_IP4_LOOKUP_N_NEXT, - .next_nodes = { - [LGPE_IP4_LOOKUP_NEXT_DROP] = "error-drop", - [LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP] = "lisp-cp-lookup", - }, -}; - -static int -lisp_gpe_rewrite (lisp_gpe_tunnel_t * t) -{ - u8 *rw = 0; - ip4_header_t * ip0; - lisp_gpe_header_t * lisp0; - ip4_udp_lisp_gpe_header_t * h0; - int len; - - len = sizeof(*h0); - - vec_validate_aligned(rw, len - 1, CLIB_CACHE_LINE_BYTES); - - h0 = (ip4_udp_lisp_gpe_header_t *) rw; - - /* Fixed portion of the (outer) ip4 header */ - ip0 = &h0->ip4; - ip0->ip_version_and_header_length = 0x45; - ip0->ttl = 254; - ip0->protocol = IP_PROTOCOL_UDP; - - /* we fix up the ip4 header length and checksum after-the-fact */ - ip0->src_address.as_u32 = t->src.as_u32; - ip0->dst_address.as_u32 = t->dst.as_u32; - ip0->checksum = ip4_header_checksum (ip0); - - /* UDP header, randomize src port on something, maybe? */ - h0->udp.src_port = clib_host_to_net_u16 (4341); - h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_lisp_gpe); - - /* LISP-gpe header */ - lisp0 = &h0->lisp; lisp0->flags = t->flags; lisp0->ver_res = t->ver_res; @@ -607,27 +91,15 @@ lisp_gpe_rewrite (lisp_gpe_tunnel_t * t) return 0; } -/* TODO remove */ -int -vnet_lisp_gpe_add_del_tunnel (vnet_lisp_gpe_add_del_tunnel_args_t *a, - u32 * sw_if_indexp) -{ - clib_warning ("UNSUPPORTED! Use vnet_lisp_gpe_add_del_fwd_entry"); - return 0; -} - #define foreach_copy_field \ _(encap_fib_index) \ _(decap_fib_index) \ _(decap_next_index) \ -_(flags) \ -_(next_protocol) \ -_(ver_res) \ -_(res) \ _(vni) static u32 -add_del_tunnel (vnet_lisp_gpe_add_del_fwd_entry_args_t *a, u32 * tun_index_res) +add_del_ip_tunnel (vnet_lisp_gpe_add_del_fwd_entry_args_t *a, + u32 * tun_index_res) { lisp_gpe_main_t * lgm = &lisp_gpe_main; lisp_gpe_tunnel_t *t = 0; @@ -635,9 +107,10 @@ add_del_tunnel (vnet_lisp_gpe_add_del_fwd_entry_args_t *a, u32 * tun_index_res) int rv; lisp_gpe_tunnel_key_t key; + /* prepare tunnel key */ memset(&key, 0, sizeof(key)); - gid_address_copy(&key.eid, &a->deid); - key.dst_loc = ip_addr_v4(&a->dlocator).as_u32; + ip_prefix_copy(&key.eid, &gid_address_ippref(&a->deid)); + ip_address_copy(&key.dst_loc, &a->dlocator); key.iid = clib_host_to_net_u32 (a->vni); p = mhash_get (&lgm->lisp_gpe_tunnel_by_key, &key); @@ -659,8 +132,19 @@ add_del_tunnel (vnet_lisp_gpe_add_del_fwd_entry_args_t *a, u32 * tun_index_res) foreach_copy_field; #undef _ - t->src = ip_addr_v4(&a->slocator); - t->dst = ip_addr_v4(&a->dlocator); + ip_address_copy(&t->src, &a->slocator); + ip_address_copy(&t->dst, &a->dlocator); + + /* if vni is non-default */ + if (a->vni) + { + t->flags = LISP_GPE_FLAGS_I; + t->vni = a->vni; + } + + t->flags |= LISP_GPE_FLAGS_P; + t->next_protocol = ip_prefix_version(&key.eid) == IP4 ? + LISP_GPE_NEXT_PROTO_IP4 : LISP_GPE_NEXT_PROTO_IP6; rv = lisp_gpe_rewrite (t); @@ -702,13 +186,20 @@ add_del_negative_fwd_entry (lisp_gpe_main_t * lgm, vnet_lisp_gpe_add_del_fwd_entry_args_t * a) { ip_adjacency_t adj; + ip_prefix_t * dpref = &gid_address_ippref(&a->deid); + ip_prefix_t * spref = &gid_address_ippref(&a->seid); + /* setup adjacency for eid */ memset (&adj, 0, sizeof(adj)); adj.n_adj = 1; - adj.explicit_fib_index = ~0; - ip_prefix_t * dpref = &gid_address_ippref(&a->deid); - ip_prefix_t * spref = &gid_address_ippref(&a->seid); + /* fill in 'legal' data to avoid issues */ + adj.lookup_next_index = (ip_prefix_version(dpref) == IP4) ? + lgm->ip4_lookup_next_lgpe_ip4_lookup : + lgm->ip6_lookup_next_lgpe_ip6_lookup; + + adj.rewrite_header.sw_if_index = ~0; + adj.rewrite_header.next_index = ~0; switch (a->action) { @@ -718,15 +209,21 @@ add_del_negative_fwd_entry (lisp_gpe_main_t * lgm, /* TODO check if route/next-hop for eid exists in fib and add * more specific for the eid with the next-hop found */ case SEND_MAP_REQUEST: - /* TODO insert tunnel that always sends map-request */ + /* insert tunnel that always sends map-request */ + adj.explicit_fib_index = (ip_prefix_version(dpref) == IP4) ? + LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP: + LGPE_IP6_LOOKUP_NEXT_LISP_CP_LOOKUP; + /* add/delete route for prefix */ + return ip_sd_fib_add_del_route (lgm, dpref, spref, a->table_id, &adj, + a->is_add); case DROP: /* for drop fwd entries, just add route, no need to add encap tunnel */ - adj.lookup_next_index = LGPE_IP4_LOOKUP_NEXT_DROP; + adj.explicit_fib_index = (ip_prefix_version(dpref) == IP4 ? + LGPE_IP4_LOOKUP_NEXT_DROP : LGPE_IP6_LOOKUP_NEXT_DROP); /* add/delete route for prefix */ - return ip4_sd_fib_add_del_route (lgm, dpref, spref, a->table_id, &adj, - a->is_add); - break; + return ip_sd_fib_add_del_route (lgm, dpref, spref, a->table_id, &adj, + a->is_add); default: return -1; } @@ -738,33 +235,47 @@ vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, { lisp_gpe_main_t * lgm = &lisp_gpe_main; ip_adjacency_t adj, * adjp; - u32 * adj_index, rv, tun_index = ~0; + u32 adj_index, rv, tun_index = ~0; ip_prefix_t * dpref, * spref; - uword * lookup_next_index, * lgpe_sw_if_index; + uword * lookup_next_index, * lgpe_sw_if_index, * lnip; + u8 ip_ver; + + if (vnet_lisp_gpe_enable_disable_status() == 0) + { + clib_warning ("LISP is disabled!"); + return VNET_API_ERROR_LISP_DISABLED; + } /* treat negative fwd entries separately */ if (a->is_negative) return add_del_negative_fwd_entry (lgm, a); + dpref = &gid_address_ippref(&a->deid); + spref = &gid_address_ippref(&a->seid); + ip_ver = ip_prefix_version(dpref); + /* add/del tunnel to tunnels pool and prepares rewrite */ - rv = add_del_tunnel (a, &tun_index); + rv = add_del_ip_tunnel (a, &tun_index); if (rv) return rv; - dpref = &gid_address_ippref(&a->deid); - spref = &gid_address_ippref(&a->seid); - /* setup adjacency for eid */ memset (&adj, 0, sizeof(adj)); adj.n_adj = 1; - adj.explicit_fib_index = ~0; + + /* fill in lookup_next_index with a 'legal' value to avoid problems */ + adj.lookup_next_index = (ip_ver == IP4) ? + lgm->ip4_lookup_next_lgpe_ip4_lookup : + lgm->ip6_lookup_next_lgpe_ip6_lookup; if (a->is_add) { /* send packets that hit this adj to lisp-gpe interface output node in * requested vrf. */ - lookup_next_index = hash_get(lgm->lgpe_ip4_lookup_next_index_by_table_id, - a->table_id); + lnip = (ip_ver == IP4) ? + lgm->lgpe_ip4_lookup_next_index_by_table_id : + lgm->lgpe_ip6_lookup_next_index_by_table_id; + lookup_next_index = hash_get(lnip, a->table_id); lgpe_sw_if_index = hash_get(lgm->lisp_gpe_hw_if_index_by_table_id, a->table_id); @@ -773,25 +284,28 @@ vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, ASSERT(lookup_next_index != 0); ASSERT(lgpe_sw_if_index != 0); - adj.lookup_next_index = lookup_next_index[0]; - adj.rewrite_header.node_index = tun_index; + /* hijack explicit fib index to store lisp interface node index and + * if_address_index for the tunnel index */ + adj.explicit_fib_index = lookup_next_index[0]; + adj.if_address_index = tun_index; adj.rewrite_header.sw_if_index = lgpe_sw_if_index[0]; } /* add/delete route for prefix */ - rv = ip4_sd_fib_add_del_route (lgm, dpref, spref, a->table_id, &adj, - a->is_add); + rv = ip_sd_fib_add_del_route (lgm, dpref, spref, a->table_id, &adj, + a->is_add); /* check that everything worked */ if (CLIB_DEBUG && a->is_add) { - adj_index = ip4_sd_fib_get_route (lgm, dpref, spref, a->table_id); + adj_index = ip_sd_fib_get_route (lgm, dpref, spref, a->table_id); ASSERT(adj_index != 0); - adjp = ip_get_adjacency (lgm->lookup_main, adj_index[0]); + adjp = ip_get_adjacency ((ip_ver == IP4) ? lgm->lm4 : lgm->lm6, + adj_index); ASSERT(adjp != 0); - ASSERT(adjp->rewrite_header.node_index == tun_index); + ASSERT(adjp->if_address_index == tun_index); } return rv; @@ -809,6 +323,7 @@ lisp_gpe_add_del_fwd_entry_command_fn (vlib_main_t * vm, gid_address_t * eids = 0, eid; clib_error_t * error = 0; u32 i; + int rv; prefp = &gid_address_ippref(&eid); @@ -861,19 +376,23 @@ lisp_gpe_add_del_fwd_entry_command_fn (vlib_main_t * vm, a.deid = eids[i]; a.slocator = slocators[i]; a.dlocator = dlocators[i]; - prefp = &gid_address_ippref(&a.deid); - a.decap_next_index = (ip_prefix_version(prefp) == IP4) ? - LISP_GPE_INPUT_NEXT_IP4_INPUT : LISP_GPE_INPUT_NEXT_IP6_INPUT; - vnet_lisp_gpe_add_del_fwd_entry (&a, 0); + rv = vnet_lisp_gpe_add_del_fwd_entry (&a, 0); + if (0 != rv) + { + error = clib_error_return(0, "failed to %s gpe maptunnel!", + is_add ? "add" : "delete"); + break; + } } done: vec_free(eids); vec_free(slocators); + vec_free(dlocators); return error; } -VLIB_CLI_COMMAND (add_del_lisp_gpe_mapping_tunnel_command, static) = { +VLIB_CLI_COMMAND (lisp_gpe_add_del_fwd_entry_command, static) = { .path = "lisp gpe maptunnel", .short_help = "lisp gpe maptunnel eid sloc " "dloc [del]", @@ -908,8 +427,8 @@ format_lisp_gpe_tunnel (u8 * s, va_list * args) s = format (s, "[%d] %U (src) %U (dst) fibs: encap %d, decap %d", t - lgm->tunnels, - format_ip4_address, &t->src, - format_ip4_address, &t->dst, + format_ip_address, &t->src, + format_ip_address, &t->dst, t->encap_fib_index, t->decap_fib_index); @@ -951,6 +470,14 @@ VLIB_CLI_COMMAND (show_lisp_gpe_tunnel_command, static) = { .function = show_lisp_gpe_tunnel_command_fn, }; +u8 +vnet_lisp_gpe_enable_disable_status(void) +{ + lisp_gpe_main_t * lgm = &lisp_gpe_main; + + return lgm->is_en; +} + clib_error_t * vnet_lisp_gpe_enable_disable (vnet_lisp_gpe_enable_disable_args_t * a) { @@ -966,10 +493,19 @@ vnet_lisp_gpe_enable_disable (vnet_lisp_gpe_enable_disable_args_t * a) vnm->vlib_main, ip4_lookup_node.index, lgpe_ip4_lookup_node.index); } + /* add lgpe_ip6_lookup as possible next_node for ip6 lookup */ + if (lgm->ip6_lookup_next_lgpe_ip6_lookup == ~0) + { + lgm->ip6_lookup_next_lgpe_ip6_lookup = vlib_node_add_next ( + vnm->vlib_main, ip6_lookup_node.index, + lgpe_ip6_lookup_node.index); + } else { /* ask cp to re-add ifaces and defaults */ } + + lgm->is_en = 1; } else { @@ -988,8 +524,9 @@ vnet_lisp_gpe_enable_disable (vnet_lisp_gpe_enable_disable_args_t * a) vec_foreach(tunnel, tunnels) { memset(at, 0, sizeof(at[0])); at->is_add = 0; - gid_address_copy(&at->deid, &tunnel->eid); - ip_addr_v4(&at->dlocator).as_u32= tunnel->dst_loc; + gid_address_type(&at->deid) = GID_ADDR_IP_PREFIX; + ip_prefix_copy(&gid_address_ippref(&at->deid), &tunnel->eid); + ip_address_copy(&at->dlocator, &tunnel->dst_loc); vnet_lisp_gpe_add_del_fwd_entry (at, 0); } vec_free(tunnels); @@ -1007,6 +544,7 @@ vnet_lisp_gpe_enable_disable (vnet_lisp_gpe_enable_disable_args_t * a) vnet_lisp_gpe_add_del_iface(ai, 0); } vec_free(table_ids); + lgm->is_en = 0; } return 0; @@ -1046,6 +584,27 @@ VLIB_CLI_COMMAND (enable_disable_lisp_gpe_command, static) = { .function = lisp_gpe_enable_disable_command_fn, }; +static clib_error_t * +lisp_show_iface_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + lisp_gpe_main_t * lgm = &lisp_gpe_main; + hash_pair_t * p; + + vlib_cli_output (vm, "%=10s%=12s", "vrf", "hw_if_index"); + hash_foreach_pair (p, lgm->lisp_gpe_hw_if_index_by_table_id, ({ + vlib_cli_output (vm, "%=10d%=10d", p->key, p->value[0]); + })); + return 0; +} + +VLIB_CLI_COMMAND (lisp_show_iface_command) = { + .path = "show lisp gpe interface", + .short_help = "show lisp gpe interface", + .function = lisp_show_iface_command_fn, +}; + clib_error_t * lisp_gpe_init (vlib_main_t *vm) { @@ -1061,15 +620,27 @@ lisp_gpe_init (vlib_main_t *vm) lgm->vnet_main = vnet_get_main(); lgm->vlib_main = vm; lgm->im4 = &ip4_main; - lgm->lookup_main = &ip4_main.lookup_main; + lgm->im6 = &ip6_main; + lgm->lm4 = &ip4_main.lookup_main; + lgm->lm6 = &ip6_main.lookup_main; lgm->ip4_lookup_next_lgpe_ip4_lookup = ~0; + lgm->ip6_lookup_next_lgpe_ip6_lookup = ~0; mhash_init (&lgm->lisp_gpe_tunnel_by_key, sizeof(uword), sizeof(lisp_gpe_tunnel_key_t)); udp_register_dst_port (vm, UDP_DST_PORT_lisp_gpe, - lisp_gpe_input_node.index, 1 /* is_ip4 */); + lisp_gpe_ip4_input_node.index, 1 /* is_ip4 */); + udp_register_dst_port (vm, UDP_DST_PORT_lisp_gpe6, + lisp_gpe_ip6_input_node.index, 0 /* is_ip4 */); return 0; } +u8 * +format_vnet_lisp_gpe_status (u8 * s, va_list * args) +{ + lisp_gpe_main_t * lgm = &lisp_gpe_main; + return format (s, "%s", lgm->is_en ? "enabled" : "disabled"); +} + VLIB_INIT_FUNCTION(lisp_gpe_init);