-}
-
-static uword
-resolver_process (vlib_main_t * vm,
- vlib_node_runtime_t * rt,
- vlib_frame_t * f)
-{
- uword event_type;
- uword *event_data = 0;
- f64 timeout = 100.0;
- vpe_api_main_t * vam = &vpe_api_main;
- pending_route_t * pr;
- vl_api_ip_add_del_route_t * adr;
- vl_api_mpls_ethernet_add_del_tunnel_2_t *pme;
- u32 * resolution_failures = 0;
- int i, rv;
- clib_error_t * e;
-
- while (1) {
- vlib_process_wait_for_event_or_clock (vm, timeout);
-
- event_type = vlib_process_get_events (vm, &event_data);
-
- switch (event_type) {
- case RESOLUTION_PENDING_EVENT:
- timeout = 1.0;
- break;
-
- case RESOLUTION_EVENT:
- for (i = 0; i < vec_len(event_data); i++) {
- /*
- * Resolution events can occur long after the
- * original request has timed out. $$$ add a cancel
- * mechanism..
- */
- if (pool_is_free_index (vam->pending_routes, event_data[i]))
- continue;
-
- pr = pool_elt_at_index (vam->pending_routes, event_data[i]);
- adr = &pr->r;
- pme = &pr->t;
-
- switch (pr->resolve_type) {
- case RESOLVE_IP4_ADD_DEL_ROUTE:
- rv = ip4_add_del_route_t_handler (adr);
- clib_warning ("resolver: add %U/%d via %U %s",
- format_ip4_address,
- (ip4_address_t *)&(adr->dst_address),
- adr->dst_address_length,
- format_ip4_address,
- (ip4_address_t *)&(adr->next_hop_address),
- (rv >= 0) ? "succeeded" : "failed");
- break;
-
- case RESOLVE_IP6_ADD_DEL_ROUTE:
- rv = ip6_add_del_route_t_handler (adr);
- clib_warning ("resolver: add %U/%d via %U %s",
- format_ip6_address,
- (ip6_address_t *)&(adr->dst_address),
- adr->dst_address_length,
- format_ip6_address,
- (ip6_address_t *)&(adr->next_hop_address),
- (rv >= 0) ? "succeeded" : "failed");
- break;
-
- case RESOLVE_MPLS_ETHERNET_ADD_DEL:
- rv = mpls_ethernet_add_del_tunnel_2_t_handler (pme);
- clib_warning ("resolver: add mpls-o-e via %U %s",
- format_ip4_address,
- (ip4_address_t *)&(pme->next_hop_ip4_address_in_outer_vrf),
- (rv >= 0) ? "succeeded" : "failed");
- break;
-
- default:
- clib_warning ("resolver: BOGUS TYPE %d", pr->resolve_type);
- }
- pool_put (vam->pending_routes, pr);
- }
- break;
-
- case IP4_ARP_EVENT:
- for (i = 0; i < vec_len(event_data); i++)
- handle_ip4_arp_event (event_data[i]);
- break;
-
- case ~0: /* timeout, retry pending resolutions */
- pool_foreach (pr, vam->pending_routes,
- ({
- int is_adr = 1;
- adr = &pr->r;
- pme = &pr->t;
-
- /* May fail, e.g. due to interface down */
- switch (pr->resolve_type) {
- case RESOLVE_IP4_ADD_DEL_ROUTE:
- e = ip4_probe_neighbor
- (vm, (ip4_address_t *)&(adr->next_hop_address),
- ntohl(adr->next_hop_sw_if_index));
- break;
-
- case RESOLVE_IP6_ADD_DEL_ROUTE:
- e = ip6_probe_neighbor
- (vm, (ip6_address_t *)&(adr->next_hop_address),
- ntohl(adr->next_hop_sw_if_index));
- break;
-
- case RESOLVE_MPLS_ETHERNET_ADD_DEL:
- is_adr = 0;
- e = ip4_probe_neighbor
- (vm,
- (ip4_address_t *)&(pme->next_hop_ip4_address_in_outer_vrf),
- pme->resolve_opaque);
- break;
-
- default:
- e = clib_error_return (0, "resolver: BOGUS TYPE %d",
- pr->resolve_type);
- }
- if (e) {
- clib_error_report (e);
- if (is_adr)
- adr->resolve_attempts = 1;
- else
- pme->resolve_attempts = 1;
-
- }
- if (is_adr) {
- adr->resolve_attempts -= 1;
- if (adr->resolve_attempts == 0)
- vec_add1 (resolution_failures,
- pr - vam->pending_routes);
- } else {
- pme->resolve_attempts -= 1;
- if (pme->resolve_attempts == 0)
- vec_add1 (resolution_failures,
- pr - vam->pending_routes);
- }
-
- }));
- for (i = 0; i < vec_len (resolution_failures); i++) {
- pr = pool_elt_at_index (vam->pending_routes,
- resolution_failures[i]);
- adr = &pr->r;
- pme = &pr->t;
-
- switch (pr->resolve_type) {
- case RESOLVE_IP4_ADD_DEL_ROUTE:
- clib_warning ("resolver: add %U/%d via %U retry failure",
- format_ip4_address,
- (ip4_address_t *)&(adr->dst_address),
- adr->dst_address_length,
- format_ip4_address,
- (ip4_address_t *)&(adr->next_hop_address));
- break;
-
- case RESOLVE_IP6_ADD_DEL_ROUTE:
- clib_warning ("resolver: add %U/%d via %U retry failure",
- format_ip6_address,
- (ip6_address_t *)&(adr->dst_address),
- adr->dst_address_length,
- format_ip6_address,
- (ip6_address_t *)&(adr->next_hop_address));
- break;
-
- case RESOLVE_MPLS_ETHERNET_ADD_DEL:
- clib_warning ("resolver: add mpls-o-e via %U retry failure",
- format_ip4_address,
- (ip4_address_t *)&(pme->next_hop_ip4_address_in_outer_vrf));
- break;
-
- default:
- clib_warning ("BUG");
- }
- pool_put(vam->pending_routes, pr);
- }
- vec_reset_length (resolution_failures);
- break;
- }
- if (pool_elts (vam->pending_routes) == 0)
- timeout = 100.0;
- vec_reset_length (event_data);
- }
- return 0; /* or not */
-}
-
-VLIB_REGISTER_NODE (vpe_resolver_process_node,static) = {
- .function = resolver_process,
- .type = VLIB_NODE_TYPE_PROCESS,
- .name = "vpe-route-resolver-process",
-};
-
-static int ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t *mp)
-{
- ip4_main_t * im = &ip4_main;
- ip_lookup_main_t * lm = &im->lookup_main;
- vnet_classify_main_t * cm = &vnet_classify_main;
- stats_main_t * sm = &stats_main;
- ip4_add_del_route_args_t a;
- ip4_address_t next_hop_address;
- u32 fib_index;
- vpe_api_main_t * vam = &vpe_api_main;
- vnet_main_t * vnm = vam->vnet_main;
- vlib_main_t * vm = vlib_get_main();
- pending_route_t * pr;
- vl_api_ip_add_del_route_t * adr;
- uword * p;
- clib_error_t * e;
- u32 ai;
- ip_adjacency_t *adj;
-
- p = hash_get (im->fib_index_by_table_id, ntohl(mp->vrf_id));
- if (!p) {
- if (mp->create_vrf_if_needed) {
- ip4_fib_t * f;
- f = find_ip4_fib_by_table_index_or_id (im, ntohl(mp->vrf_id),
- 0 /* flags */);
- fib_index = f->index;
- } else {
- /* No such VRF, and we weren't asked to create one */
- return VNET_API_ERROR_NO_SUCH_FIB;
- }
- } else {
- fib_index = p[0];
- }
-
- if (~0 != mp->next_hop_sw_if_index &&
- pool_is_free_index (vnm->interface_main.sw_interfaces,
- ntohl(mp->next_hop_sw_if_index)))
- return VNET_API_ERROR_NO_MATCHING_INTERFACE;
-
- clib_memcpy (next_hop_address.data, mp->next_hop_address,
- sizeof (next_hop_address.data));
-
- /* Arp for the next_hop if necessary */
- if (mp->is_add && mp->resolve_if_needed && ~0 != mp->next_hop_sw_if_index) {
- u32 lookup_result;
- ip_adjacency_t * adj;
-
- lookup_result = ip4_fib_lookup_with_table
- (im, fib_index, &next_hop_address, 1 /* disable default route */);
-
- adj = ip_get_adjacency (lm, lookup_result);
-
- if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP) {
- pool_get (vam->pending_routes, pr);
- pr->resolve_type = RESOLVE_IP4_ADD_DEL_ROUTE;
- adr = &pr->r;
- clib_memcpy (adr, mp, sizeof (*adr));
- /* recursion block, "just in case" */
- adr->resolve_if_needed = 0;
- adr->resolve_attempts = ntohl(mp->resolve_attempts);
- vnet_register_ip4_arp_resolution_event
- (vnm, &next_hop_address, vpe_resolver_process_node.index,
- RESOLUTION_EVENT, pr - vam->pending_routes);
-
- vlib_process_signal_event
- (vm, vpe_resolver_process_node.index,
- RESOLUTION_PENDING_EVENT, 0 /* data */);
-
- /* The interface may be down, etc. */
- e = ip4_probe_neighbor
- (vm, (ip4_address_t *)&(mp->next_hop_address),
- ntohl(mp->next_hop_sw_if_index));
-
- if (e)
- clib_error_report(e);
-
- return VNET_API_ERROR_IN_PROGRESS;
- }
- }
-
- if (mp->is_multipath) {
- u32 flags;
-
- dslock (sm, 1 /* release hint */, 10 /* tag */);
-
- if (mp->is_add)
- flags = IP4_ROUTE_FLAG_ADD;
- else
- flags = IP4_ROUTE_FLAG_DEL;
-
- if (mp->not_last)
- flags |= IP4_ROUTE_FLAG_NOT_LAST_IN_GROUP;
-
- ip4_add_del_route_next_hop (im, flags,
- (ip4_address_t *) mp->dst_address,
- (u32) mp->dst_address_length,
- (ip4_address_t *) mp->next_hop_address,
- ntohl(mp->next_hop_sw_if_index),
- (u32) mp->next_hop_weight,
- ~0 /* adj_index */,
- fib_index);
- dsunlock(sm);
- return 0;
- }
-
- memset (&a, 0, sizeof (a));
- clib_memcpy (a.dst_address.data, mp->dst_address, sizeof (a.dst_address.data));
-
- a.dst_address_length = mp->dst_address_length;
-
- a.flags = (mp->is_add ? IP4_ROUTE_FLAG_ADD : IP4_ROUTE_FLAG_DEL);
- a.flags |= IP4_ROUTE_FLAG_FIB_INDEX;
- a.table_index_or_table_id = fib_index;
- a.add_adj = 0;
- a.n_add_adj = 0;
-
- if (mp->not_last)
- a.flags |= IP4_ROUTE_FLAG_NOT_LAST_IN_GROUP;
-
- dslock (sm, 1 /* release hint */, 2 /* tag */);
-
- if (mp->is_add) {
- if (mp->is_drop)
- ai = lm->drop_adj_index;
- else if (mp->is_local)
- ai = lm->local_adj_index;
- else if (mp->is_classify) {
- if (pool_is_free_index (cm->tables, ntohl(mp->classify_table_index))) {
- dsunlock(sm);
- return VNET_API_ERROR_NO_SUCH_TABLE;
- }
- adj = ip_add_adjacency (lm,
- /* template */ 0,
- /* block size */ 1,
- &ai);
-
- adj->lookup_next_index = IP_LOOKUP_NEXT_CLASSIFY;
- adj->classify.table_index = ntohl(mp->classify_table_index);
- }
- else if (mp->lookup_in_vrf) {
- p = hash_get (im->fib_index_by_table_id, ntohl(mp->lookup_in_vrf));
- if (p) {
- adj = ip_add_adjacency (lm,
- /* template */ 0,
- /* block size */ 1,
- &ai);
- adj->explicit_fib_index = p[0];
- }
- else {
- dsunlock(sm);
- return VNET_API_ERROR_NO_SUCH_INNER_FIB;
- }
- }
- else
- ai = ip4_route_get_next_hop_adj (im,
- fib_index,
- &next_hop_address,
- ntohl(mp->next_hop_sw_if_index),
- fib_index);
-
- if (ai == lm->miss_adj_index) {
- dsunlock(sm);
- return VNET_API_ERROR_NO_SUCH_INNER_FIB;
- }
- } else {
- ip_adjacency_t * adj;
- int disable_default_route = 1;
-
- /* Trying to delete the default route? */
- if (a.dst_address.as_u32 == 0 &&
- a.dst_address_length == 0)
- disable_default_route = 0;
-
- ai = ip4_fib_lookup_with_table
- (im, fib_index, &a.dst_address, disable_default_route);
- if (ai == lm->miss_adj_index) {
- dsunlock(sm);
- return VNET_API_ERROR_UNKNOWN_DESTINATION;
- }
-
- adj = ip_get_adjacency (lm, ai);
- if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP) {
- dsunlock(sm);
- return VNET_API_ERROR_ADDRESS_MATCHES_INTERFACE_ADDRESS;
- }
- }
-
- a.adj_index = ai;
- ip4_add_del_route (im, &a);
-
- dsunlock (sm);
- return 0;
-}
-
-static int ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t *mp)
-{
- ip6_main_t * im = &ip6_main;
- ip_lookup_main_t * lm = &im->lookup_main;
- vnet_main_t * vnm = vnet_get_main();
- vlib_main_t * vm = vlib_get_main();
- vpe_api_main_t * vam = &vpe_api_main;
- stats_main_t * sm = &stats_main;
- ip6_add_del_route_args_t a;
- ip6_address_t next_hop_address;
- pending_route_t * pr;
- vl_api_ip_add_del_route_t * adr;
-
- u32 fib_index;
- uword * p;
- clib_error_t * e;
- ip_adjacency_t *adj = 0;
- u32 ai;
-
- p = hash_get (im->fib_index_by_table_id, ntohl(mp->vrf_id));
-
- if (!p) {
- if (mp->create_vrf_if_needed) {
- ip6_fib_t * f;
- f = find_ip6_fib_by_table_index_or_id (im, ntohl(mp->vrf_id),
- 0 /* flags */);
- fib_index = f->index;
- } else {
- /* No such VRF, and we weren't asked to create one */
- return VNET_API_ERROR_NO_SUCH_FIB;
- }
- } else {
- fib_index = p[0];
- }
-
- if (~0 != mp->next_hop_sw_if_index &&
- pool_is_free_index (vnm->interface_main.sw_interfaces,
- ntohl(mp->next_hop_sw_if_index)))
- return VNET_API_ERROR_NO_MATCHING_INTERFACE;
-
- clib_memcpy (next_hop_address.as_u8, mp->next_hop_address,
- sizeof (next_hop_address.as_u8));
-
- /* Arp for the next_hop if necessary */
- if (mp->is_add && mp->resolve_if_needed && ~0 != mp->next_hop_sw_if_index) {
- u32 lookup_result;
- ip_adjacency_t * adj;
-
- lookup_result = ip6_fib_lookup_with_table
- (im, fib_index, &next_hop_address);
-
- adj = ip_get_adjacency (lm, lookup_result);
-
- if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP) {
- pool_get (vam->pending_routes, pr);
- adr = &pr->r;
- pr->resolve_type = RESOLVE_IP6_ADD_DEL_ROUTE;
- clib_memcpy (adr, mp, sizeof (*adr));
- /* recursion block, "just in case" */
- adr->resolve_if_needed = 0;
- adr->resolve_attempts = ntohl(mp->resolve_attempts);
- vnet_register_ip6_neighbor_resolution_event
- (vnm, &next_hop_address, vpe_resolver_process_node.index,
- RESOLUTION_EVENT, pr - vam->pending_routes);
-
- vlib_process_signal_event
- (vm, vpe_resolver_process_node.index,
- RESOLUTION_PENDING_EVENT, 0 /* data */);
-
- /* The interface may be down, etc. */
- e = ip6_probe_neighbor
- (vm, (ip6_address_t *)&(mp->next_hop_address),
- ntohl(mp->next_hop_sw_if_index));
-
- if (e)
- clib_error_report(e);
-
- return VNET_API_ERROR_IN_PROGRESS;
- }
- }
-
- if (mp->is_multipath) {
- u32 flags;
-
- dslock (sm, 1 /* release hint */, 11 /* tag */);
-
- if (mp->is_add)
- flags = IP6_ROUTE_FLAG_ADD;
- else
- flags = IP6_ROUTE_FLAG_DEL;
-
- if (mp->not_last)
- flags |= IP6_ROUTE_FLAG_NOT_LAST_IN_GROUP;
-
- ip6_add_del_route_next_hop (im, flags, (ip6_address_t *)mp->dst_address,
- (u32) mp->dst_address_length,
- (ip6_address_t *)mp->next_hop_address,
- ntohl(mp->next_hop_sw_if_index),
- (u32) mp->next_hop_weight,
- ~0 /* adj_index */,
- fib_index);
- dsunlock(sm);
- return 0;
- }
-
- memset (&a, 0, sizeof (a));
- clib_memcpy (a.dst_address.as_u8, mp->dst_address, sizeof (a.dst_address.as_u8));
-
- a.dst_address_length = mp->dst_address_length;
-
- a.flags = (mp->is_add ? IP6_ROUTE_FLAG_ADD : IP6_ROUTE_FLAG_DEL);
- a.flags |= IP6_ROUTE_FLAG_FIB_INDEX;
- a.table_index_or_table_id = fib_index;
- a.add_adj = 0;
- a.n_add_adj = 0;
-
- if (mp->not_last)
- a.flags |= IP6_ROUTE_FLAG_NOT_LAST_IN_GROUP;
-
- dslock (sm, 1 /* release hint */, 3 /* tag */);
-
- if (mp->is_add) {
- if (mp->is_drop)
- ai = lm->drop_adj_index;
- else if (mp->is_local)
- ai = lm->local_adj_index;
- else if (mp->lookup_in_vrf) {
- p = hash_get (im->fib_index_by_table_id, ntohl(mp->lookup_in_vrf));
- if (p) {
- adj = ip_add_adjacency (lm,
- /* template */ 0,
- /* block size */ 1,
- &ai);
- adj->explicit_fib_index = p[0];
- }
- else {
- dsunlock(sm);
- return VNET_API_ERROR_NO_SUCH_INNER_FIB;
- }