avf: properly set irq queue masks
[vpp.git] / src / plugins / dns / resolver_process.c
1 /*
2  * Copyright (c) 2017 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <dns/dns.h>
17 #include <vlibapi/api.h>
18 #include <vlibmemory/api.h>
19
20 #include <vlib/vlib.h>
21 #include <vnet/vnet.h>
22
23 /* define message IDs */
24 #include <dns/dns_msg_enum.h>
25
26 #define vl_typedefs             /* define message structures */
27 #include <dns/dns_all_api_h.h>
28 #undef vl_typedefs
29
30 #define vl_endianfun            /* define message structures */
31 #include <dns/dns_all_api_h.h>
32 #undef vl_endianfun
33
34 /* instantiate all the print functions we know about */
35 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
36 #define vl_printfun
37 #include <dns/dns_all_api_h.h>
38 #undef vl_printfun
39
40 #include <vlibapi/api_helper_macros.h>
41
42 int
43 vnet_dns_response_to_reply (u8 * response,
44                             vl_api_dns_resolve_name_reply_t * rmp,
45                             u32 * min_ttlp);
46 int
47 vnet_dns_response_to_name (u8 * response,
48                            vl_api_dns_resolve_ip_reply_t * rmp,
49                            u32 * min_ttlp);
50
51 static void
52 resolve_event (dns_main_t * dm, f64 now, u8 * reply)
53 {
54   vlib_main_t *vm = dm->vlib_main;
55   dns_pending_request_t *pr;
56   dns_header_t *d;
57   u32 pool_index;
58   dns_cache_entry_t *ep;
59   u32 min_ttl;
60   u16 flags;
61   u16 rcode;
62   int i;
63   int entry_was_valid;
64   int remove_count;
65   int rv = 0;
66
67   d = (dns_header_t *) reply;
68   flags = clib_net_to_host_u16 (d->flags);
69   rcode = flags & DNS_RCODE_MASK;
70
71   /* $$$ u16 limits cache to 65K entries, fix later multiple dst ports */
72   pool_index = clib_net_to_host_u16 (d->id);
73   dns_cache_lock (dm);
74
75   if (pool_is_free_index (dm->entries, pool_index))
76     {
77       vec_free (reply);
78       if (0)
79         clib_warning ("pool index %d is free", pool_index);
80       vlib_node_increment_counter (vm, dns46_reply_node.index,
81                                    DNS46_REPLY_ERROR_NO_ELT, 1);
82       dns_cache_unlock (dm);
83       return;
84     }
85
86   ep = pool_elt_at_index (dm->entries, pool_index);
87
88   if (ep->dns_response)
89     vec_free (ep->dns_response);
90
91   /* Handle [sic] recursion AKA CNAME indirection */
92   rv = vnet_dns_cname_indirection_nolock (dm, pool_index, reply);
93
94   /* CNAME found, further resolution pending, we're done here */
95   if (rv > 0)
96     {
97       dns_cache_unlock (dm);
98       return;
99     }
100   /* Server backfire: refused to answer, or sent zero replies */
101   if (rv < 0)
102     {
103       /* Try a different server */
104       if (ep->server_af /* ip6 */ )
105         {
106           if (0)
107             clib_warning ("Server %U failed to resolve '%s'",
108                           format_ip6_address,
109                           dm->ip6_name_servers + ep->server_rotor, ep->name);
110           /* Any more servers to try? */
111           if (ep->server_fails > 1 || vec_len (dm->ip6_name_servers) <= 1)
112             {
113               /* No, tell the client to go away */
114               goto reply;
115             }
116           ep->retry_count = 0;
117           ep->server_rotor++;
118           ep->server_fails++;
119           if (ep->server_rotor >= vec_len (dm->ip6_name_servers))
120             ep->server_rotor = 0;
121           if (0)
122             clib_warning ("Try server %U", format_ip6_address,
123                           dm->ip6_name_servers + ep->server_rotor);
124           vnet_dns_send_dns6_request
125             (dm, ep, dm->ip6_name_servers + ep->server_rotor);
126         }
127       else
128         {
129           if (0)
130             clib_warning ("Server %U failed to resolve '%s'",
131                           format_ip4_address,
132                           dm->ip4_name_servers + ep->server_rotor, ep->name);
133
134           if (ep->server_fails > 1 || vec_len (dm->ip4_name_servers) <= 1)
135             {
136               /* No, tell the client to go away */
137               goto reply;
138             }
139           ep->retry_count = 0;
140           ep->server_rotor++;
141           ep->server_fails++;
142           if (ep->server_rotor >= vec_len (dm->ip4_name_servers))
143             ep->server_rotor = 0;
144           if (0)
145             clib_warning ("Try server %U", format_ip4_address,
146                           dm->ip4_name_servers + ep->server_rotor);
147           vnet_dns_send_dns4_request
148             (dm, ep, dm->ip4_name_servers + ep->server_rotor);
149         }
150       dns_cache_unlock (dm);
151       return;
152     }
153
154 reply:
155   /* Save the response */
156   ep->dns_response = reply;
157
158   /*
159    * Pick a sensible default cache entry expiration time.
160    * We don't play the 10-second timeout game.
161    */
162   ep->expiration_time = now + 600.0;
163
164   if (0)
165     clib_warning ("resolving '%s', was %s valid",
166                   ep->name, (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID) ?
167                   "already" : "not");
168   /*
169    * The world is a mess. A single DNS request sent to e.g. 8.8.8.8
170    * may yield multiple, subtly different responses - all with the same
171    * DNS protocol-level ID.
172    *
173    * Last response wins in terms of what ends up in the cache.
174    * First response wins in terms of the response sent to the client.
175    */
176
177   /* Strong hint that we may not find a pending resolution entry */
178   entry_was_valid = (ep->flags & DNS_CACHE_ENTRY_FLAG_VALID) ? 1 : 0;
179
180   if (vec_len (ep->dns_response))
181     ep->flags |= DNS_CACHE_ENTRY_FLAG_VALID;
182
183   /* Most likely, send 1 message */
184   for (i = 0; i < vec_len (ep->pending_requests); i++)
185     {
186       vl_api_registration_t *regp;
187
188       pr = vec_elt_at_index (ep->pending_requests, i);
189
190       switch (pr->request_type)
191         {
192         case DNS_API_PENDING_NAME_TO_IP:
193           {
194             vl_api_dns_resolve_name_reply_t *rmp;
195             regp = vl_api_client_index_to_registration (pr->client_index);
196             if (regp == 0)
197               continue;
198
199             rmp = vl_msg_api_alloc (sizeof (*rmp));
200             rmp->_vl_msg_id =
201               clib_host_to_net_u16 (VL_API_DNS_RESOLVE_NAME_REPLY
202                                     + dm->msg_id_base);
203             rmp->context = pr->client_context;
204             min_ttl = ~0;
205             rv = vnet_dns_response_to_reply (ep->dns_response, rmp, &min_ttl);
206             if (min_ttl != ~0)
207               ep->expiration_time = now + min_ttl;
208             rmp->retval = clib_host_to_net_u32 (rv);
209             vl_api_send_msg (regp, (u8 *) rmp);
210           }
211           break;
212
213         case DNS_API_PENDING_IP_TO_NAME:
214           {
215             vl_api_dns_resolve_ip_reply_t *rmp;
216
217             regp = vl_api_client_index_to_registration (pr->client_index);
218             if (regp == 0)
219               continue;
220
221             rmp = vl_msg_api_alloc (sizeof (*rmp));
222             rmp->_vl_msg_id =
223               clib_host_to_net_u16 (VL_API_DNS_RESOLVE_IP_REPLY
224                                     + dm->msg_id_base);
225             rmp->context = pr->client_context;
226             min_ttl = ~0;
227             rv = vnet_dns_response_to_name (ep->dns_response, rmp, &min_ttl);
228             if (min_ttl != ~0)
229               ep->expiration_time = now + min_ttl;
230             rmp->retval = clib_host_to_net_u32 (rv);
231             vl_api_send_msg (regp, (u8 *) rmp);
232           }
233           break;
234
235         case DNS_PEER_PENDING_IP_TO_NAME:
236         case DNS_PEER_PENDING_NAME_TO_IP:
237           if (pr->is_ip6)
238             vnet_send_dns6_reply (dm, pr, ep, 0 /* allocate a buffer */ );
239           else
240             vnet_send_dns4_reply (dm, pr, ep, 0 /* allocate a buffer */ );
241           break;
242         default:
243           clib_warning ("request type %d unknown", pr->request_type);
244           break;
245         }
246     }
247   vec_free (ep->pending_requests);
248
249   remove_count = 0;
250   for (i = 0; i < vec_len (dm->unresolved_entries); i++)
251     {
252       if (dm->unresolved_entries[i] == pool_index)
253         {
254           vec_delete (dm->unresolved_entries, 1, i);
255           remove_count++;
256           i--;
257         }
258     }
259   /* See multiple response comment above... */
260   if (remove_count == 0)
261     {
262       u32 error_code = entry_was_valid ? DNS46_REPLY_ERROR_MULTIPLE_REPLY :
263         DNS46_REPLY_ERROR_NO_UNRESOLVED_ENTRY;
264
265       vlib_node_increment_counter (vm, dns46_reply_node.index, error_code, 1);
266       dns_cache_unlock (dm);
267       return;
268     }
269
270   /* Deal with bogus names, server issues, etc. */
271   switch (rcode)
272     {
273     default:
274     case DNS_RCODE_NO_ERROR:
275       break;
276
277     case DNS_RCODE_SERVER_FAILURE:
278     case DNS_RCODE_NOT_IMPLEMENTED:
279     case DNS_RCODE_REFUSED:
280       if (ep->server_af == 0)
281         clib_warning ("name server %U can't resolve '%s'",
282                       format_ip4_address,
283                       dm->ip4_name_servers + ep->server_rotor, ep->name);
284       else
285         clib_warning ("name server %U can't resolve '%s'",
286                       format_ip6_address,
287                       dm->ip6_name_servers + ep->server_rotor, ep->name);
288       /* FALLTHROUGH */
289     case DNS_RCODE_NAME_ERROR:
290     case DNS_RCODE_FORMAT_ERROR:
291       /* remove trash from the cache... */
292       vnet_dns_delete_entry_by_index_nolock (dm, ep - dm->entries);
293       break;
294     }
295
296
297   dns_cache_unlock (dm);
298   return;
299 }
300
301 static void
302 retry_scan (dns_main_t * dm, f64 now)
303 {
304   int i;
305   dns_cache_entry_t *ep;
306
307   for (i = 0; i < vec_len (dm->unresolved_entries); i++)
308     {
309       dns_cache_lock (dm);
310       ep = pool_elt_at_index (dm->entries, dm->unresolved_entries[i]);
311
312       ASSERT ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID) == 0);
313       vnet_send_dns_request (dm, ep);
314       dns_cache_unlock (dm);
315     }
316 }
317
318 static uword
319 dns_resolver_process (vlib_main_t * vm,
320                       vlib_node_runtime_t * rt, vlib_frame_t * f)
321 {
322   dns_main_t *dm = &dns_main;
323   f64 now;
324   f64 timeout = 1000.0;
325   uword *event_data = 0;
326   uword event_type;
327   int i;
328
329   while (1)
330     {
331       vlib_process_wait_for_event_or_clock (vm, timeout);
332
333       now = vlib_time_now (vm);
334
335       event_type = vlib_process_get_events (vm, (uword **) & event_data);
336
337       switch (event_type)
338         {
339           /* Send one of these when a resolution is pending */
340         case DNS_RESOLVER_EVENT_PENDING:
341           timeout = 2.0;
342           break;
343
344         case DNS_RESOLVER_EVENT_RESOLVED:
345           for (i = 0; i < vec_len (event_data); i++)
346             resolve_event (dm, now, (u8 *) event_data[i]);
347           break;
348
349         case ~0:                /* timeout */
350           retry_scan (dm, now);
351           break;
352         }
353       vec_reset_length (event_data);
354
355       /* No work? Back to slow timeout mode... */
356       if (vec_len (dm->unresolved_entries) == 0)
357         timeout = 1000.0;
358     }
359   return 0;                     /* or not */
360 }
361
362 void
363 vnet_dns_create_resolver_process (dns_main_t * dm)
364 {
365   /* Already created the resolver process? */
366   if (dm->resolver_process_node_index > 0)
367     return;
368
369   /* No, create it now and make a note of the node index */
370   dm->resolver_process_node_index = vlib_process_create
371     (dm->vlib_main, "dns-resolver-process",
372      dns_resolver_process, 16 /* log2_n_stack_bytes */ );
373 }
374
375 /*
376  * fd.io coding-style-patch-verification: ON
377  *
378  * Local Variables:
379  * eval: (c-set-style "gnu")
380  * End:
381  */