ip4 network request processing 26/9226/2
authorDave Barach <dave@barachs.net>
Sat, 4 Nov 2017 13:44:38 +0000 (09:44 -0400)
committerDamjan Marion <dmarion.lists@gmail.com>
Sun, 5 Nov 2017 11:37:08 +0000 (11:37 +0000)
Change-Id: I6eb0681cc2595f81ac3bf5ffa3e9b2adfff04a36
Signed-off-by: Dave Barach <dave@barachs.net>
src/vnet.am
src/vnet/dns/dns.c
src/vnet/dns/dns.h
src/vnet/dns/reply_node.c
src/vnet/dns/request_node.c [new file with mode: 0644]
src/vnet/dns/resolver_process.c

index 6483e06..1997394 100644 (file)
@@ -820,6 +820,7 @@ libvnet_la_SOURCES +=                               \
  vnet/dns/dns.h                                        \
  vnet/dns/dns_packet.h                         \
  vnet/dns/reply_node.c                         \
+ vnet/dns/request_node.c                       \
  vnet/dns/resolver_process.c
 
 nobase_include_HEADERS +=                      \
index d3f573d..d361aa1 100644 (file)
@@ -55,9 +55,7 @@ dns_cache_clear (dns_main_t * dm)
   pool_foreach (ep, dm->entries,
   ({
     vec_free (ep->name);
-    vec_free (ep->pending_api_requests);
-    vec_free (ep->ip4_peers_to_notify);
-    vec_free (ep->ip6_peers_to_notify);
+    vec_free (ep->pending_requests);
   }));
   /* *INDENT-ON* */
 
@@ -472,7 +470,7 @@ name_to_labels (u8 * name)
  * Produces a non-NULL-terminated u8 *vector. %v format is your friend.
  */
 u8 *
-labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
+vnet_dns_labels_to_name (u8 * label, u8 * full_text, u8 ** parse_from_here)
 {
   u8 *reply = 0;
   u16 offset;
@@ -646,9 +644,7 @@ vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index)
 found:
   hash_unset_mem (dm->cache_entry_by_name, ep->name);
   vec_free (ep->name);
-  vec_free (ep->pending_api_requests);
-  vec_free (ep->ip4_peers_to_notify);
-  vec_free (ep->ip6_peers_to_notify);
+  vec_free (ep->pending_requests);
   pool_put (dm->entries, ep);
 
   return 0;
@@ -766,16 +762,16 @@ dns_add_static_entry (dns_main_t * dm, u8 * name, u8 * dns_reply_data)
   return 0;
 }
 
-static int
-dns_resolve_name (dns_main_t * dm,
-                 u8 * name, u32 client_index, u32 client_context,
-                 u32 request_type, dns_cache_entry_t ** retp)
+int
+vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t,
+                      dns_cache_entry_t ** retp)
 {
   dns_cache_entry_t *ep;
   int rv;
   f64 now;
   uword *p;
-  pending_api_request_t *pr;
+  dns_pending_request_t *pr;
+  int count;
 
   now = vlib_time_now (dm->vlib_main);
 
@@ -850,11 +846,10 @@ search_again:
        {
          /*
           * Resolution pending. Add request to the pending vector
+          * by copying the template request
           */
-         vec_add2 (ep->pending_api_requests, pr, 1);
-         pr->request_type = request_type;
-         pr->client_index = client_index;
-         pr->client_context = client_context;
+         vec_add2 (ep->pending_requests, pr, 1);
+         memcpy (pr, t, sizeof (*pr));
          dns_cache_unlock (dm);
          return (0);
        }
@@ -882,19 +877,38 @@ re_resolve:
   hash_set_mem (dm->cache_entry_by_name, ep->name, ep - dm->entries);
 
   vec_add1 (dm->unresolved_entries, ep - dm->entries);
-  vec_add2 (ep->pending_api_requests, pr, 1);
-  pr->request_type = request_type;
-  pr->client_index = client_index;
-  pr->client_context = client_context;
+  vec_add2 (ep->pending_requests, pr, 1);
+
+  pr->request_type = t->request_type;
+
+  /* Remember details so we can reply later... */
+  if (t->request_type == DNS_API_PENDING_NAME_TO_IP ||
+      t->request_type == DNS_API_PENDING_IP_TO_NAME)
+    {
+      pr->client_index = t->client_index;
+      pr->client_context = t->client_context;
+    }
+  else
+    {
+      pr->client_index = ~0;
+      pr->is_ip6 = t->is_ip6;
+      pr->dst_port = t->dst_port;
+      pr->id = t->id;
+      pr->name = t->name;
+      if (t->is_ip6)
+       count = 16;
+      else
+       count = 4;
+      clib_memcpy (pr->dst_address, t->dst_address, count);
+    }
+
   vnet_send_dns_request (dm, ep);
   dns_cache_unlock (dm);
   return 0;
 }
 
 #define foreach_notification_to_move            \
-_(pending_api_requests)                                \
-_(ip4_peers_to_notify)                          \
-_(ip6_peers_to_notify)
+_(pending_requests)
 
 /**
  * Handle cname indirection. JFC. Called with the cache locked.
@@ -977,7 +991,7 @@ vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply)
 found_last_request:
 
   now = vlib_time_now (dm->vlib_main);
-  cname = labels_to_name (rr->rdata, reply, &pos2);
+  cname = vnet_dns_labels_to_name (rr->rdata, reply, &pos2);
   /* Save the cname */
   vec_add1 (cname, 0);
   _vec_len (cname) -= 1;
@@ -1275,7 +1289,7 @@ vnet_dns_response_to_name (u8 * response,
       switch (clib_net_to_host_u16 (rr->type))
        {
        case DNS_TYPE_PTR:
-         name = labels_to_name (rr->rdata, response, &junk);
+         name = vnet_dns_labels_to_name (rr->rdata, response, &junk);
          memcpy (rmp->name, name, vec_len (name));
          ttl = clib_net_to_host_u32 (rr->ttl);
          if (*min_ttlp)
@@ -1303,13 +1317,17 @@ vl_api_dns_resolve_name_t_handler (vl_api_dns_resolve_name_t * mp)
   dns_main_t *dm = &dns_main;
   vl_api_dns_resolve_name_reply_t *rmp;
   dns_cache_entry_t *ep;
+  dns_pending_request_t _t0, *t0 = &_t0;
   int rv;
 
   /* Sanitize the name slightly */
   mp->name[ARRAY_LEN (mp->name) - 1] = 0;
 
-  rv = dns_resolve_name (dm, mp->name, mp->client_index, mp->context,
-                        DNS_API_PENDING_NAME_TO_IP, &ep);
+  t0->request_type = DNS_API_PENDING_NAME_TO_IP;
+  t0->client_index = mp->client_index;
+  t0->client_context = mp->context;
+
+  rv = vnet_dns_resolve_name (dm, mp->name, t0, &ep);
 
   /* Error, e.g. not enabled? Tell the user */
   if (rv < 0)
@@ -1347,6 +1365,7 @@ vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
   int i, len;
   u8 *lookup_name = 0;
   u8 digit, nybble;
+  dns_pending_request_t _t0, *t0 = &_t0;
 
   if (mp->is_ip6)
     {
@@ -1382,8 +1401,11 @@ vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
 
   vec_add1 (lookup_name, 0);
 
-  rv = dns_resolve_name (dm, lookup_name, mp->client_index, mp->context,
-                        DNS_API_PENDING_IP_TO_NAME, &ep);
+  t0->request_type = DNS_API_PENDING_IP_TO_NAME;
+  t0->client_index = mp->client_index;
+  t0->client_context = mp->context;
+
+  rv = vnet_dns_resolve_name (dm, lookup_name, t0, &ep);
 
   vec_free (lookup_name);
 
@@ -1407,7 +1429,7 @@ vl_api_dns_resolve_ip_t_handler (vl_api_dns_resolve_ip_t * mp)
   /* *INDENT-ON* */
 
   /*
-   * dns_resolve_name leaves the cache locked when it returns
+   * vnet_dns_resolve_name leaves the cache locked when it returns
    * a cached result, so unlock it here.
    */
   dns_cache_unlock (dm);
@@ -1488,13 +1510,11 @@ dns_init (vlib_main_t * vm)
   udp_register_dst_port (vm, UDP_DST_PORT_dns_reply6, dns46_reply_node.index,
                         0 /* is_ip4 */ );
 
-#if 0
   udp_register_dst_port (vm, UDP_DST_PORT_dns, dns4_request_node.index,
                         1 /* is_ip4 */ );
+
   udp_register_dst_port (vm, UDP_DST_PORT_dns6, dns6_request_node.index,
                         0 /* is_ip4 */ );
-#endif
-
   return 0;
 }
 
@@ -2095,7 +2115,7 @@ format_dns_cache (u8 * s, va_list * args)
 
             if (verbose > 2)
               s = format (s, "    %d client notifications pending\n",
-                          vec_len(ep->pending_api_requests));
+                          vec_len(ep->pending_requests));
           }
       }
     else
@@ -2501,6 +2521,258 @@ VLIB_CLI_COMMAND (test_dns_expire_command) =
 /* *INDENT-ON* */
 #endif
 
+void
+vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * pr,
+                     dns_cache_entry_t * ep, vlib_buffer_t * b0)
+{
+  clib_warning ("Unimplemented...");
+}
+
+
+void
+vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * pr,
+                     dns_cache_entry_t * ep, vlib_buffer_t * b0)
+{
+  vlib_main_t *vm = dm->vlib_main;
+  u32 bi;
+  fib_prefix_t prefix;
+  fib_node_index_t fei;
+  u32 sw_if_index, fib_index;
+  ip4_main_t *im4 = &ip4_main;
+  ip_lookup_main_t *lm4 = &im4->lookup_main;
+  ip_interface_address_t *ia = 0;
+  ip4_address_t *src_address;
+  ip4_header_t *ip;
+  udp_header_t *udp;
+  dns_header_t *dh;
+  vlib_frame_t *f;
+  u32 *to_next;
+  u8 *dns_response;
+  u8 *reply;
+  vl_api_dns_resolve_name_reply_t _rnr, *rnr = &_rnr;
+  vl_api_dns_resolve_ip_reply_t _rir, *rir = &_rir;
+  u32 ttl, tmp;
+  u32 qp_offset;
+  dns_query_t *qp;
+  dns_rr_t *rr;
+  u8 *rrptr;
+  int is_fail = 0;
+
+  ASSERT (ep && ep->dns_response);
+
+  if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
+    {
+      /* Quick and dirty way to dig up the A-record address. $$ FIXME */
+      memset (rnr, 0, sizeof (*rnr));
+      if (vnet_dns_response_to_reply (ep->dns_response, rnr, &ttl))
+       {
+         /* clib_warning ("response_to_reply failed..."); */
+         is_fail = 1;
+       }
+      if (rnr->ip4_set == 0)
+       {
+         /* clib_warning ("No A-record..."); */
+         is_fail = 1;
+       }
+    }
+  else if (pr->request_type == DNS_PEER_PENDING_IP_TO_NAME)
+    {
+      memset (rir, 0, sizeof (*rir));
+      if (vnet_dns_response_to_name (ep->dns_response, rir, &ttl))
+       {
+         /* clib_warning ("response_to_name failed..."); */
+         is_fail = 1;
+       }
+    }
+  else
+    {
+      clib_warning ("Unknown request type %d", pr->request_type);
+      return;
+    }
+
+  /* Initialize a buffer */
+  if (b0 == 0)
+    {
+      if (vlib_buffer_alloc (vm, &bi, 1) != 1)
+       return;
+      b0 = vlib_get_buffer (vm, bi);
+    }
+
+  if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
+    vlib_buffer_free_one (vm, b0->next_buffer);
+
+  /*
+   * Reset the buffer. We recycle the DNS request packet in the cache
+   * hit case, and reply immediately from the request node.
+   *
+   * In the resolution-required / deferred case, resetting a freshly-allocated
+   * buffer won't hurt. We hope.
+   */
+  b0->flags &= VLIB_BUFFER_FREE_LIST_INDEX_MASK;
+  b0->flags |= (VNET_BUFFER_F_LOCALLY_ORIGINATED
+               | VLIB_BUFFER_TOTAL_LENGTH_VALID);
+  b0->current_data = 0;
+  b0->current_length = 0;
+  b0->total_length_not_including_first_buffer = 0;
+  vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;  /* "local0" */
+  vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0;  /* default VRF for now */
+
+  /* Find a FIB path to the peer we're trying to answer */
+  clib_memcpy (&prefix.fp_addr.ip4, pr->dst_address, sizeof (ip4_address_t));
+  prefix.fp_proto = FIB_PROTOCOL_IP4;
+  prefix.fp_len = 32;
+
+  fib_index = fib_table_find (prefix.fp_proto, 0 /* default VRF for now */ );
+  if (fib_index == (u32) ~ 0)
+    {
+      clib_warning ("no fib table");
+      return;
+    }
+
+  fei = fib_table_lookup (fib_index, &prefix);
+
+  /* Couldn't find route to destination. Bail out. */
+  if (fei == FIB_NODE_INDEX_INVALID)
+    {
+      clib_warning ("no route to DNS server");
+      return;
+    }
+
+  sw_if_index = fib_entry_get_resolving_interface (fei);
+
+  if (sw_if_index == ~0)
+    {
+      clib_warning
+       ("route to %U exists, fei %d, get_resolving_interface returned"
+        " ~0", fei, format_ip4_address, &prefix.fp_addr);
+      return;
+    }
+
+  /* *INDENT-OFF* */
+  foreach_ip_interface_address(lm4, ia, sw_if_index, 1 /* honor unnummbered */,
+  ({
+    src_address = ip_interface_address_get_address (lm4, ia);
+    goto found_src_address;
+  }));
+  /* *INDENT-ON* */
+
+  clib_warning ("FIB BUG");
+  return;
+
+found_src_address:
+
+  ip = vlib_buffer_get_current (b0);
+  udp = (udp_header_t *) (ip + 1);
+  dns_response = (u8 *) (udp + 1);
+  memset (ip, 0, sizeof (*ip) + sizeof (*udp));
+
+  /*
+   * Start with the variadic portion of the exercise.
+   * Turn the name into a set of DNS "labels". Max length
+   * per label is 63, enforce that.
+   */
+  reply = name_to_labels (pr->name);
+  vec_free (pr->name);
+
+  qp_offset = vec_len (reply);
+
+  /* Add space for the query header */
+  vec_validate (reply, qp_offset + sizeof (dns_query_t) - 1);
+
+  qp = (dns_query_t *) (reply + qp_offset);
+
+  if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
+    qp->type = clib_host_to_net_u16 (DNS_TYPE_A);
+  else
+    qp->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
+
+  qp->class = clib_host_to_net_u16 (DNS_CLASS_IN);
+
+  /* Punch in space for the dns_header_t */
+  vec_insert (reply, sizeof (dns_header_t), 0);
+
+  dh = (dns_header_t *) reply;
+
+  /* Transaction ID = pool index */
+  dh->id = pr->id;
+
+  /* Announce that we did a recursive lookup */
+  tmp = DNS_AA | DNS_RA | DNS_RD | DNS_OPCODE_QUERY | DNS_QR;
+  if (is_fail)
+    tmp |= DNS_RCODE_NAME_ERROR;
+  dh->flags = clib_host_to_net_u16 (tmp);
+  dh->qdcount = clib_host_to_net_u16 (1);
+  dh->anscount = (is_fail == 0) ? clib_host_to_net_u16 (1) : 0;
+  dh->nscount = 0;
+  dh->arcount = 0;
+
+  /* If the name resolution worked, cough up an appropriate RR */
+  if (is_fail == 0)
+    {
+      /* Add the answer. First, a name pointer (0xC00C) */
+      vec_add1 (reply, 0xC0);
+      vec_add1 (reply, 0x0C);
+
+      /* Now, add single A-rec RR */
+      if (pr->request_type == DNS_PEER_PENDING_NAME_TO_IP)
+       {
+         vec_add2 (reply, rrptr, sizeof (dns_rr_t) + sizeof (ip4_address_t));
+         rr = (dns_rr_t *) rrptr;
+
+         rr->type = clib_host_to_net_u16 (DNS_TYPE_A);
+         rr->class = clib_host_to_net_u16 (1 /* internet */ );
+         rr->ttl = clib_host_to_net_u32 (ttl);
+         rr->rdlength = clib_host_to_net_u16 (sizeof (ip4_address_t));
+         clib_memcpy (rr->rdata, rnr->ip4_address, sizeof (ip4_address_t));
+       }
+      else
+       {
+         /* Or a single PTR RR */
+         u8 *vecname = format (0, "%s", rir->name);
+         u8 *label_vec = name_to_labels (vecname);
+         vec_free (vecname);
+
+         vec_add2 (reply, rrptr, sizeof (dns_rr_t) + vec_len (label_vec));
+         rr = (dns_rr_t *) rrptr;
+         rr->type = clib_host_to_net_u16 (DNS_TYPE_PTR);
+         rr->class = clib_host_to_net_u16 (1 /* internet */ );
+         rr->ttl = clib_host_to_net_u32 (ttl);
+         rr->rdlength = clib_host_to_net_u16 (vec_len (label_vec));
+         clib_memcpy (rr->rdata, label_vec, vec_len (label_vec));
+         vec_free (label_vec);
+       }
+    }
+  clib_memcpy (dns_response, reply, vec_len (reply));
+
+  /* Set the packet length */
+  b0->current_length = sizeof (*ip) + sizeof (*udp) + vec_len (reply);
+
+  /* IP header */
+  ip->ip_version_and_header_length = 0x45;
+  ip->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
+  ip->ttl = 255;
+  ip->protocol = IP_PROTOCOL_UDP;
+  ip->src_address.as_u32 = src_address->as_u32;
+  clib_memcpy (ip->dst_address.as_u8, pr->dst_address,
+              sizeof (ip4_address_t));
+  ip->checksum = ip4_header_checksum (ip);
+
+  /* UDP header */
+  udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dns);
+  udp->dst_port = pr->dst_port;
+  udp->length = clib_host_to_net_u16 (sizeof (udp_header_t) +
+                                     vec_len (reply));
+  udp->checksum = 0;
+  vec_free (reply);
+
+  /* Ship it to ip4_lookup */
+  f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
+  to_next = vlib_frame_vector_args (f);
+  to_next[0] = bi;
+  f->n_vectors = 1;
+  vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
+}
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
index 442ef86..84d7ee0 100644 (file)
@@ -29,10 +29,21 @@ typedef struct
   u32 request_type;
   u32 client_index;
   u32 client_context;
-} pending_api_request_t;
+  u8 is_ip6;
+  u16 dst_port;
+  u16 id;
+  u16 pad;
+  u8 dst_address[16];
+  u8 *name;
+} dns_pending_request_t;
 
-#define DNS_API_PENDING_NAME_TO_IP 1
-#define DNS_API_PENDING_IP_TO_NAME 2
+typedef enum
+{
+  DNS_API_PENDING_NAME_TO_IP = 1,
+  DNS_API_PENDING_IP_TO_NAME,
+  DNS_PEER_PENDING_NAME_TO_IP,
+  DNS_PEER_PENDING_IP_TO_NAME,
+} dns_pending_request_type_t;
 
 typedef struct
 {
@@ -60,10 +71,8 @@ typedef struct
   /** Cached dns response */
   u8 *dns_response;
 
-  /** Clients awaiting responses */
-  pending_api_request_t *pending_api_requests;
-  ip4_address_t *ip4_peers_to_notify;
-  ip6_address_t *ip6_peers_to_notify;
+  /** Clients / peers awaiting responses */
+  dns_pending_request_t *pending_requests;
 } dns_cache_entry_t;
 
 #define DNS_CACHE_ENTRY_FLAG_VALID     (1<<0) /**< we have Actual Data */
@@ -108,8 +117,27 @@ typedef struct
 extern dns_main_t dns_main;
 
 extern vlib_node_registration_t dns46_reply_node;
+extern vlib_node_registration_t dns4_request_node;
+extern vlib_node_registration_t dns6_request_node;
 extern vlib_node_registration_t dns_resolver_node;
 
+#define foreach_dns46_request_error                                     \
+_(NONE, "No error")                                                    \
+_(UNIMPLEMENTED, "Unimplemented")                                       \
+_(PROCESSED, "DNS request pkts processed")                              \
+_(IP_OPTIONS, "DNS pkts with ip options (dropped)")                     \
+_(BAD_REQUEST, "DNS pkts with serious discrepanices (dropped)")         \
+_(TOO_MANY_REQUESTS, "DNS pkts asking too many questions")              \
+_(RESOLUTION_REQUIRED, "DNS pkts pending upstream name resolution")
+
+typedef enum
+{
+#define _(sym,str) DNS46_REQUEST_ERROR_##sym,
+  foreach_dns46_request_error
+#undef _
+    DNS46_REQUEST_N_ERROR,
+} dns46_request_error_t;
+
 #define foreach_dns46_reply_error                       \
 _(PROCESSED, "DNS reply pkts processed")                \
 _(NO_ELT, "No DNS pool element")                        \
@@ -130,6 +158,19 @@ vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply);
 
 int vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index);
 
+int
+vnet_dns_resolve_name (dns_main_t * dm, u8 * name, dns_pending_request_t * t,
+                      dns_cache_entry_t ** retp);
+
+void vnet_send_dns4_reply (dns_main_t * dm, dns_pending_request_t * t,
+                          dns_cache_entry_t * ep, vlib_buffer_t * b0);
+
+void vnet_send_dns6_reply (dns_main_t * dm, dns_pending_request_t * t,
+                          dns_cache_entry_t * ep, vlib_buffer_t * b0);
+
+u8 *vnet_dns_labels_to_name (u8 * label, u8 * full_text,
+                            u8 ** parse_from_here);
+
 format_function_t format_dns_reply;
 
 static inline void
index e045ba8..fbb99e8 100644 (file)
@@ -192,18 +192,22 @@ dns46_reply_node_fn (vlib_main_t * vm,
   return frame->n_vectors;
 }
 
+/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (dns46_reply_node) =
 {
-  .function = dns46_reply_node_fn,.name = "dns46_reply",.vector_size =
-    sizeof (u32),.format_trace = format_dns46_reply_trace,.type =
-    VLIB_NODE_TYPE_INTERNAL,.n_errors =
-    ARRAY_LEN (dns46_reply_error_strings),.error_strings =
-    dns46_reply_error_strings,.n_next_nodes = DNS46_REPLY_N_NEXT,
-    /* edit / add dispositions here */
-    .next_nodes =
-  {
-  [DNS46_REPLY_NEXT_DROP] = "error-drop",}
-,};
+  .function = dns46_reply_node_fn,
+  .name = "dns46_reply",
+  .vector_size = sizeof (u32),
+  .format_trace = format_dns46_reply_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (dns46_reply_error_strings),
+  .error_strings = dns46_reply_error_strings,
+  .n_next_nodes = DNS46_REPLY_N_NEXT,
+  .next_nodes = {
+    [DNS46_REPLY_NEXT_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
 
 /*
  * fd.io coding-style-patch-verification: ON
diff --git a/src/vnet/dns/request_node.c b/src/vnet/dns/request_node.c
new file mode 100644 (file)
index 0000000..6446880
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2017 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.
+ */
+
+#include <vnet/dns/dns.h>
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+vlib_node_registration_t dns46_request_node;
+
+typedef struct
+{
+  u32 pool_index;
+  u32 disposition;
+} dns46_request_trace_t;
+
+/* packet trace format function */
+static u8 *
+format_dns46_request_trace (u8 * s, va_list * args)
+{
+  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+  dns46_request_trace_t *t = va_arg (*args, dns46_request_trace_t *);
+
+  s = format (s, "DNS46_REPLY: pool index %d, disposition  %d",
+             t->pool_index, t->disposition);
+  return s;
+}
+
+vlib_node_registration_t dns46_request_node;
+
+static char *dns46_request_error_strings[] = {
+#define _(sym,string) string,
+  foreach_dns46_request_error
+#undef _
+};
+
+typedef enum
+{
+  DNS46_REQUEST_NEXT_DROP,
+  DNS46_REQUEST_NEXT_IP_LOOKUP,
+  DNS46_REQUEST_N_NEXT,
+} dns46_request_next_t;
+
+static uword
+dns46_request_inline (vlib_main_t * vm,
+                     vlib_node_runtime_t * node, vlib_frame_t * frame,
+                     int is_ip6)
+{
+  u32 n_left_from, *from, *to_next;
+  dns46_request_next_t next_index;
+  dns_main_t *dm = &dns_main;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_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);
+
+#if 0
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         u32 next0 = DNS46_REQUEST_NEXT_INTERFACE_OUTPUT;
+         u32 next1 = DNS46_REQUEST_NEXT_INTERFACE_OUTPUT;
+         u32 sw_if_index0, sw_if_index1;
+         u8 tmp0[6], tmp1[6];
+         ethernet_header_t *en0, *en1;
+         u32 bi0, bi1;
+         vlib_buffer_t *b0, *b1;
+
+         /* 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, CLIB_CACHE_LINE_BYTES, STORE);
+           CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
+         }
+
+         /* speculatively enqueue b0 and b1 to the current next frame */
+         to_next[0] = bi0 = from[0];
+         to_next[1] = bi1 = from[1];
+         from += 2;
+         to_next += 2;
+         n_left_from -= 2;
+         n_left_to_next -= 2;
+
+         b0 = vlib_get_buffer (vm, bi0);
+         b1 = vlib_get_buffer (vm, bi1);
+
+         /* $$$$$ End of processing 2 x packets $$$$$ */
+
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
+           {
+             if (b0->flags & VLIB_BUFFER_IS_TRACED)
+               {
+                 dns46_request_trace_t *t =
+                   vlib_add_trace (vm, node, b0, sizeof (*t));
+                 t->sw_if_index = sw_if_index0;
+                 t->next_index = next0;
+               }
+             if (b1->flags & VLIB_BUFFER_IS_TRACED)
+               {
+                 dns46_request_trace_t *t =
+                   vlib_add_trace (vm, node, b1, sizeof (*t));
+                 t->sw_if_index = sw_if_index1;
+                 t->next_index = next1;
+               }
+           }
+
+         /* verify speculative enqueues, maybe switch current next frame */
+         vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
+                                          to_next, n_left_to_next,
+                                          bi0, bi1, next0, next1);
+       }
+#endif
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         u32 bi0;
+         vlib_buffer_t *b0;
+         u32 next0 = DNS46_REQUEST_NEXT_DROP;
+         u32 error0 = DNS46_REQUEST_ERROR_NONE;
+         udp_header_t *u0;
+         dns_header_t *d0;
+         dns_query_t *q0;
+         ip4_header_t *ip40 = 0;
+         ip6_header_t *ip60 = 0;
+         dns_cache_entry_t *ep0;
+         dns_pending_request_t _t0, *t0 = &_t0;
+         u16 flags0;
+         u32 pool_index0 = ~0;
+         u8 *name0;
+         u8 *label0;
+
+         /* speculatively enqueue b0 to the current next frame */
+         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);
+         d0 = vlib_buffer_get_current (b0);
+         u0 = (udp_header_t *) ((u8 *) d0 - sizeof (*u0));
+         if (is_ip6)
+           {
+             ip60 = (ip6_header_t *) (((u8 *) u0) - sizeof (ip4_header_t));
+             error0 = DNS46_REQUEST_ERROR_UNIMPLEMENTED;
+             goto done0;
+           }
+         else
+           {
+             ip40 = (ip4_header_t *) (((u8 *) u0) - sizeof (ip4_header_t));
+             if (ip40->ip_version_and_header_length != 0x45)
+               {
+                 error0 = DNS46_REQUEST_ERROR_IP_OPTIONS;
+                 goto done0;
+               }
+           }
+         /* Parse through the DNS request */
+         flags0 = clib_net_to_host_u16 (d0->flags);
+
+         /* Requests only */
+         if (flags0 & DNS_QR)
+           {
+             error0 = DNS46_REQUEST_ERROR_BAD_REQUEST;
+             goto done0;
+           }
+         if (clib_net_to_host_u16 (d0->qdcount) != 1)
+           {
+             error0 = DNS46_REQUEST_ERROR_TOO_MANY_REQUESTS;
+             goto done0;
+           }
+
+         label0 = (u8 *) (d0 + 1);
+
+         name0 = vnet_dns_labels_to_name (label0, (u8 *) d0, (u8 **) & q0);
+
+         t0->request_type = DNS_PEER_PENDING_NAME_TO_IP;
+
+         /*
+          * See if this is a reverse lookup. Both ip4 and ip6 reverse
+          * requests end with ".arpa"
+          */
+         if (PREDICT_TRUE (vec_len (name0) > 5))
+           {
+             u8 *aptr0 = name0 + vec_len (name0) - 5;
+
+             if (!memcmp (aptr0, ".arpa", 5))
+               t0->request_type = DNS_PEER_PENDING_IP_TO_NAME;
+           }
+
+         t0->client_index = ~0;
+         t0->is_ip6 = is_ip6;
+         t0->dst_port = u0->src_port;
+         t0->id = d0->id;
+         t0->name = name0;
+         if (is_ip6)
+           clib_memcpy (t0->dst_address, ip60->src_address.as_u8,
+                        sizeof (ip6_address_t));
+         else
+           clib_memcpy (t0->dst_address, ip40->src_address.as_u8,
+                        sizeof (ip4_address_t));
+
+         vnet_dns_resolve_name (dm, name0, t0, &ep0);
+
+         if (ep0)
+           {
+             if (is_ip6)
+               vnet_send_dns6_reply (dm, t0, ep0, b0);
+             else
+               vnet_send_dns4_reply (dm, t0, ep0, b0);
+             next0 = DNS46_REQUEST_NEXT_IP_LOOKUP;
+           }
+         else
+           {
+             error0 = DNS46_REQUEST_ERROR_RESOLUTION_REQUIRED;
+           }
+
+       done0:
+         b0->error = node->errors[error0];
+
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
+                            && (b0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             dns46_request_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->disposition = error0;
+             t->pool_index = pool_index0;
+           }
+
+         /* verify speculative enqueue, maybe switch current next frame */
+         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 frame->n_vectors;
+}
+
+static uword
+dns4_request_node_fn (vlib_main_t * vm,
+                     vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+
+  return dns46_request_inline (vm, node, frame, 0 /* is_ip6 */ );
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (dns4_request_node) =
+{
+  .function = dns4_request_node_fn,
+  .name = "dns4-request",
+  .vector_size = sizeof (u32),
+  .format_trace = format_dns46_request_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (dns46_request_error_strings),
+  .error_strings = dns46_request_error_strings,
+  .n_next_nodes = DNS46_REQUEST_N_NEXT,
+  .next_nodes = {
+    [DNS46_REQUEST_NEXT_DROP] = "error-drop",
+    [DNS46_REQUEST_NEXT_IP_LOOKUP] = "ip4-lookup",
+  },
+};
+/* *INDENT-ON* */
+
+static uword
+dns6_request_node_fn (vlib_main_t * vm,
+                     vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+
+  return dns46_request_inline (vm, node, frame, 1 /* is_ip6 */ );
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (dns6_request_node) =
+{
+  .function = dns6_request_node_fn,
+  .name = "dns6-request",
+  .vector_size = sizeof (u32),
+  .format_trace = format_dns46_request_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (dns46_request_error_strings),
+  .error_strings = dns46_request_error_strings,
+  .n_next_nodes = DNS46_REQUEST_N_NEXT,
+  .next_nodes = {
+    [DNS46_REQUEST_NEXT_DROP] = "error-drop",
+    [DNS46_REQUEST_NEXT_IP_LOOKUP] = "ip6-lookup",
+  },
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index f473422..23bbd3b 100644 (file)
@@ -53,6 +53,7 @@ static void
 resolve_event (dns_main_t * dm, f64 now, u8 * reply)
 {
   vlib_main_t *vm = dm->vlib_main;
+  dns_pending_request_t *pr;
   dns_header_t *d;
   u32 pool_index;
   dns_cache_entry_t *ep;
@@ -99,51 +100,68 @@ resolve_event (dns_main_t * dm, f64 now, u8 * reply)
     ep->flags |= DNS_CACHE_ENTRY_FLAG_VALID;
 
   /* Most likely, send 1 message */
-  for (i = 0; i < vec_len (ep->pending_api_requests); i++)
+  for (i = 0; i < vec_len (ep->pending_requests); i++)
     {
       vl_api_registration_t *regp;
 
-      regp = vl_api_client_index_to_registration
-       (ep->pending_api_requests[i].client_index);
+      pr = vec_elt_at_index (ep->pending_requests, i);
 
-      if (regp == 0)
-       continue;
-
-      if (ep->pending_api_requests[i].request_type
-         == DNS_API_PENDING_NAME_TO_IP)
-       {
-         vl_api_dns_resolve_name_reply_t *rmp;
-         rmp = vl_msg_api_alloc (sizeof (*rmp));
-         rmp->_vl_msg_id =
-           clib_host_to_net_u16 (VL_API_DNS_RESOLVE_NAME_REPLY);
-         rmp->context = ep->pending_api_requests[i].client_context;
-         min_ttl = ~0;
-         rv = vnet_dns_response_to_reply (ep->dns_response, rmp, &min_ttl);
-         if (min_ttl != ~0)
-           ep->expiration_time = now + min_ttl;
-         rmp->retval = clib_host_to_net_u32 (rv);
-         vl_msg_api_send (regp, (u8 *) rmp);
-       }
-      else
+      switch (pr->request_type)
        {
-         vl_api_dns_resolve_ip_reply_t *rmp;
-         rmp = vl_msg_api_alloc (sizeof (*rmp));
-         rmp->_vl_msg_id =
-           clib_host_to_net_u16 (VL_API_DNS_RESOLVE_IP_REPLY);
-         rmp->context = ep->pending_api_requests[i].client_context;
-         min_ttl = ~0;
-         rv = vnet_dns_response_to_name (ep->dns_response, rmp, &min_ttl);
-         if (min_ttl != ~0)
-           ep->expiration_time = now + min_ttl;
-         rmp->retval = clib_host_to_net_u32 (rv);
-         vl_msg_api_send (regp, (u8 *) rmp);
+       case DNS_API_PENDING_NAME_TO_IP:
+         {
+           vl_api_dns_resolve_name_reply_t *rmp;
+           regp = vl_api_client_index_to_registration (pr->client_index);
+           if (regp == 0)
+             continue;
+
+           rmp = vl_msg_api_alloc (sizeof (*rmp));
+           rmp->_vl_msg_id =
+             clib_host_to_net_u16 (VL_API_DNS_RESOLVE_NAME_REPLY);
+           rmp->context = pr->client_context;
+           min_ttl = ~0;
+           rv = vnet_dns_response_to_reply (ep->dns_response, rmp, &min_ttl);
+           if (min_ttl != ~0)
+             ep->expiration_time = now + min_ttl;
+           rmp->retval = clib_host_to_net_u32 (rv);
+           vl_msg_api_send (regp, (u8 *) rmp);
+         }
+         break;
+
+       case DNS_API_PENDING_IP_TO_NAME:
+         {
+           vl_api_dns_resolve_ip_reply_t *rmp;
+
+           regp = vl_api_client_index_to_registration (pr->client_index);
+           if (regp == 0)
+             continue;
+
+           rmp = vl_msg_api_alloc (sizeof (*rmp));
+           rmp->_vl_msg_id =
+             clib_host_to_net_u16 (VL_API_DNS_RESOLVE_IP_REPLY);
+           rmp->context = pr->client_context;
+           min_ttl = ~0;
+           rv = vnet_dns_response_to_name (ep->dns_response, rmp, &min_ttl);
+           if (min_ttl != ~0)
+             ep->expiration_time = now + min_ttl;
+           rmp->retval = clib_host_to_net_u32 (rv);
+           vl_msg_api_send (regp, (u8 *) rmp);
+         }
+         break;
+
+       case DNS_PEER_PENDING_IP_TO_NAME:
+       case DNS_PEER_PENDING_NAME_TO_IP:
+         if (pr->is_ip6)
+           vnet_send_dns6_reply (dm, pr, ep, 0 /* allocate a buffer */ );
+         else
+           vnet_send_dns4_reply (dm, pr, ep, 0 /* allocate a buffer */ );
+         break;
+       default:
+         clib_warning ("request type %d unknown", pr->request_type);
+         break;
        }
     }
-  vec_free (ep->pending_api_requests);
-
-  /* $$$ Add ip4/ip6 reply code */
-  vec_free (ep->ip4_peers_to_notify);
-  vec_free (ep->ip6_peers_to_notify);
+  vec_free (ep->pending_requests);
 
   for (i = 0; i < vec_len (dm->unresolved_entries); i++)
     {