VPP-1027: DNS name resolver

This patch is a plausible first-cut, suitable for initial testing by
vcl (host stack client library).

Main features;
- recursive name resolution
- multiple ip4/ip6 name servers
- cache size limit enforcement
  - currently limited to 65K
- ttl / aging
- static mapping support
- show / clear / debug CLI commands

Binary APIs provided for the following:
- add/delete name servers
- enable/disable the name cache
- resolve a name

To Do list:
- Respond to ip4/ip6 client DNS requests (vs. binary API requests)
- Perf / scale tuning
  - map pending transaction ids to pool indices, so the cache
    can (greatly) exceed 65K entries
- Security improvements
  - Use unpredictable dns transaction IDs, related to previous item
  - Make sure that response-packet src ip addresses match the server
- Add binary APIs
  - deliver raw response data to clients
  - control recursive name resolution
- Documentation

Change-Id: I48c373d5c05d7108ccd814d4055caf8c75ca10b7
Signed-off-by: Dave Barach <dave@barachs.net>
This commit is contained in:
Dave Barach
2017-10-10 17:53:14 -04:00
committed by Florin Coras
parent 7e550693df
commit 6545716c07
14 changed files with 3205 additions and 9 deletions
+172 -5
View File
@@ -2179,6 +2179,39 @@ static void vl_api_memfd_segment_create_reply_t_handler_json
clib_warning ("no");
}
static void vl_api_dns_resolve_name_reply_t_handler
(vl_api_dns_resolve_name_reply_t * mp)
{
vat_main_t *vam = &vat_main;
i32 retval = ntohl (mp->retval);
if (vam->async_mode)
{
vam->async_errors += (retval < 0);
}
else
{
vam->retval = retval;
vam->result_ready = 1;
if (retval == 0)
{
if (mp->ip4_set)
clib_warning ("ip4 address %U", format_ip4_address,
(ip4_address_t *) mp->ip4_address);
if (mp->ip6_set)
clib_warning ("ip6 address %U", format_ip6_address,
(ip6_address_t *) mp->ip6_address);
}
else
clib_warning ("retval %d", retval);
}
}
static void vl_api_dns_resolve_name_reply_t_handler_json
(vl_api_dns_resolve_name_reply_t * mp)
{
clib_warning ("no");
}
static void vl_api_ip_address_details_t_handler
(vl_api_ip_address_details_t * mp)
@@ -5066,8 +5099,8 @@ _(want_stats_reply) \
_(cop_interface_enable_disable_reply) \
_(cop_whitelist_enable_disable_reply) \
_(sw_interface_clear_stats_reply) \
_(ioam_enable_reply) \
_(ioam_disable_reply) \
_(ioam_enable_reply) \
_(ioam_disable_reply) \
_(one_add_del_locator_reply) \
_(one_add_del_local_eid_reply) \
_(one_add_del_remote_mapping_reply) \
@@ -5117,7 +5150,9 @@ _(p2p_ethernet_del_reply) \
_(lldp_config_reply) \
_(sw_interface_set_lldp_reply) \
_(tcp_configure_src_addresses_reply) \
_(app_namespace_add_del_reply)
_(app_namespace_add_del_reply) \
_(dns_enable_disable_reply) \
_(dns_name_server_add_del_reply)
#define _(n) \
static void vl_api_##n##_t_handler \
@@ -5422,7 +5457,10 @@ _(P2P_ETHERNET_DEL_REPLY, p2p_ethernet_del_reply) \
_(LLDP_CONFIG_REPLY, lldp_config_reply) \
_(SW_INTERFACE_SET_LLDP_REPLY, sw_interface_set_lldp_reply) \
_(TCP_CONFIGURE_SRC_ADDRESSES_REPLY, tcp_configure_src_addresses_reply) \
_(APP_NAMESPACE_ADD_DEL_REPLY, app_namespace_add_del_reply)
_(APP_NAMESPACE_ADD_DEL_REPLY, app_namespace_add_del_reply) \
_(DNS_ENABLE_DISABLE_REPLY, dns_enable_disable_reply) \
_(DNS_NAME_SERVER_ADD_DEL_REPLY, dns_name_server_add_del_reply) \
_(DNS_RESOLVE_NAME_REPLY, dns_resolve_name_reply)
#define foreach_standalone_reply_msg \
_(SW_INTERFACE_EVENT, sw_interface_event) \
@@ -5432,7 +5470,7 @@ _(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters) \
_(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters) \
_(VNET_IP4_NBR_COUNTERS, vnet_ip4_nbr_counters) \
_(VNET_IP6_NBR_COUNTERS, vnet_ip6_nbr_counters) \
_(MEMFD_SEGMENT_CREATE_REPLY, memfd_segment_create_reply)
_(MEMFD_SEGMENT_CREATE_REPLY, memfd_segment_create_reply) \
typedef struct
{
@@ -20830,6 +20868,132 @@ api_memfd_segment_create (vat_main_t * vam)
return ret;
}
static int
api_dns_enable_disable (vat_main_t * vam)
{
unformat_input_t *line_input = vam->input;
vl_api_dns_enable_disable_t *mp;
u8 enable_disable = 1;
int ret;
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (line_input, "disable"))
enable_disable = 0;
if (unformat (line_input, "enable"))
enable_disable = 1;
else
break;
}
/* Construct the API message */
M (DNS_ENABLE_DISABLE, mp);
mp->enable = enable_disable;
/* send it... */
S (mp);
/* Wait for the reply */
W (ret);
return ret;
}
static int
api_dns_resolve_name (vat_main_t * vam)
{
unformat_input_t *line_input = vam->input;
vl_api_dns_resolve_name_t *mp;
u8 *name = 0;
int ret;
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (line_input, "%s", &name))
;
else
break;
}
if (vec_len (name) > 127)
{
errmsg ("name too long");
return -99;
}
/* Construct the API message */
M (DNS_RESOLVE_NAME, mp);
memcpy (mp->name, name, vec_len (name));
vec_free (name);
/* send it... */
S (mp);
/* Wait for the reply */
W (ret);
return ret;
}
static int
api_dns_name_server_add_del (vat_main_t * vam)
{
unformat_input_t *i = vam->input;
vl_api_dns_name_server_add_del_t *mp;
u8 is_add = 1;
ip6_address_t ip6_server;
ip4_address_t ip4_server;
int ip6_set = 0;
int ip4_set = 0;
int ret = 0;
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "%U", unformat_ip6_address, &ip6_server))
ip6_set = 1;
else if (unformat (i, "%U", unformat_ip4_address, &ip4_server))
ip4_set = 1;
else if (unformat (i, "del"))
is_add = 0;
else
{
clib_warning ("parse error '%U'", format_unformat_error, i);
return -99;
}
}
if (ip4_set && ip6_set)
{
errmsg ("Only one server address allowed per message");
return -99;
}
if ((ip4_set + ip6_set) == 0)
{
errmsg ("Server address required");
return -99;
}
/* Construct the API message */
M (DNS_NAME_SERVER_ADD_DEL, mp);
if (ip6_set)
{
memcpy (mp->server_address, &ip6_server, sizeof (ip6_address_t));
mp->is_ip6 = 1;
}
else
{
memcpy (mp->server_address, &ip4_server, sizeof (ip4_address_t));
mp->is_ip6 = 0;
}
mp->is_add = is_add;
/* send it... */
S (mp);
/* Wait for a reply, return good/bad news */
W (ret);
return ret;
}
static int
q_or_quit (vat_main_t * vam)
{
@@ -21621,6 +21785,9 @@ _(sw_interface_set_lldp, "<intfc> | sw_if_index <nn> [port-desc <description>]\n
_(tcp_configure_src_addresses, "<ip4|6>first-<ip4|6>last [vrf <id>]") \
_(memfd_segment_create,"size <nnn>") \
_(app_namespace_add_del, "[add] id <ns-id> secret <nn> sw_if_index <nn>")\
_(dns_enable_disable, "[enable][disable]") \
_(dns_name_server_add_del, "<ip-address> [del]") \
_(dns_resolve_name, "<hostname>")
/* List of command functions, CLI names map directly to functions */
#define foreach_cli_function \
+16 -1
View File
@@ -665,7 +665,22 @@ vl_msg_api_config (vl_msg_api_msg_config_t * c)
{
api_main_t *am = &api_main;
ASSERT (c->id > 0);
/*
* This happens during the java core tests if the message
* dictionary is missing newly added xxx_reply_t messages.
* Should never happen, but since I shot myself in the foot once
* this way, I thought I'd make it easy to debug if I ever do
* it again... (;-)...
*/
if (c->id == 0)
{
if (c->name)
clib_warning ("Trying to register %s with a NULL msg id!", c->name);
else
clib_warning ("Trying to register a NULL msg with a NULL msg id!");
clib_warning ("Did you forget to call setup_message_id_table?");
return;
}
#define _(a) vec_validate (am->a, c->id);
foreach_msg_api_vector;
+16
View File
@@ -812,6 +812,22 @@ nobase_include_HEADERS += \
API_FILES += vnet/span/span.api
########################################
# DNS proxy, API
########################################
libvnet_la_SOURCES += \
vnet/dns/dns.c \
vnet/dns/dns.h \
vnet/dns/dns_packet.h \
vnet/dns/reply_node.c \
vnet/dns/resolver_process.c
nobase_include_HEADERS += \
vnet/dns/dns.api.h \
vnet/dns/dns.h
API_FILES += vnet/dns/dns.api
########################################
# Packet generator
########################################
+8
View File
@@ -122,6 +122,14 @@ _(APP_WRONG_NS_SECRET, -129, "Wrong app namespace secret") \
_(APP_CONNECT_SCOPE, -130, "Connect scope") \
_(APP_ALREADY_ATTACHED, -131, "App already attached") \
_(SESSION_REDIRECT, -132, "Redirect failed") \
_(ILLEGAL_NAME, -133, "Illegal name") \
_(NO_NAME_SERVERS, -134, "No name servers configured") \
_(NAME_SERVER_NOT_FOUND, -135, "Name server not found") \
_(NAME_RESOLUTION_NOT_ENABLED, -136, "Name resolution not enabled") \
_(NAME_SERVER_FORMAT_ERROR, -137, "Server format error (bug!)") \
_(NAME_SERVER_NO_SUCH_NAME, -138, "No such name") \
_(NAME_SERVER_NO_ADDRESSES, -139, "No addresses available") \
_(NAME_SERVER_NEXT_SERVER, -140, "Retry with new server")
typedef enum
{
+66
View File
@@ -0,0 +1,66 @@
/*
* 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.
*/
vl_api_version 1.0.0
/** \brief enable/disable name resolution
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param is_enable - 1 = enable, 0 = disable
*/
autoreply define dns_enable_disable {
u32 client_index;
u32 context;
u8 enable;
};
/** \brief add or delete an upstream name server
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param is_ip6 - an ip6 name server
@param is_add - add = 1, delete = 0
@param server_address - server ip address
*/
autoreply define dns_name_server_add_del {
u32 client_index;
u32 context;
u8 is_ip6;
u8 is_add;
u8 server_address[16];
};
/** \brief DNS name resolution request
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param name - the name to resolve
*/
define dns_resolve_name {
u32 client_index;
u32 context;
u8 name[128];
};
define dns_resolve_name_reply {
u32 context;
i32 retval;
u8 ip4_set;
u8 ip6_set;
u8 ip4_address[4];
u8 ip6_address[16];
};
+2114
View File
File diff suppressed because it is too large Load Diff
+149
View File
@@ -0,0 +1,149 @@
/*
* 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.
*/
#ifndef included_dns_h
#define included_dns_h
#include <vppinfra/time.h>
#include <vppinfra/cache.h>
#include <vppinfra/error.h>
#include <vppinfra/hash.h>
#include <vnet/dns/dns_packet.h>
#include <vnet/ip/ip.h>
typedef struct
{
/** flags */
volatile u8 flags;
/** The name in "normal human being" notation, e.g. www.foobar.com */
u8 *name;
/** Expiration time */
f64 expiration_time;
/** Cached dns request, for sending retries */
u8 *dns_request;
/** Retry parameters */
int retry_count;
int server_rotor;
int server_af;
f64 retry_timer;
/** Cached dns response */
u8 *dns_response;
/** Clients awaiting responses */
u32 *api_clients_to_notify;
u32 *api_client_contexts;
ip4_address_t *ip4_peers_to_notify;
ip6_address_t *ip6_peers_to_notify;
} dns_cache_entry_t;
#define DNS_CACHE_ENTRY_FLAG_VALID (1<<0) /**< we have Actual Data */
#define DNS_CACHE_ENTRY_FLAG_STATIC (1<<1) /**< static entry */
#define DNS_RETRIES_PER_SERVER 3
#define DNS_RESOLVER_EVENT_RESOLVED 1
#define DNS_RESOLVER_EVENT_PENDING 2
typedef struct
{
/** Pool of cache entries */
dns_cache_entry_t *entries;
/** Pool indices of unresolved entries */
u32 *unresolved_entries;
/** Find cached record by name */
uword *cache_entry_by_name;
uword *cache_lock;
/** enable / disable flag */
int is_enabled;
/** upstream name servers, e.g. 8.8.8.8 */
ip4_address_t *ip4_name_servers;
ip6_address_t *ip6_name_servers;
/** config parameters */
u32 name_cache_size;
u32 max_ttl_in_seconds;
u32 random_seed;
/* convenience */
vlib_main_t *vlib_main;
vnet_main_t *vnet_main;
} dns_main_t;
extern dns_main_t dns_main;
extern vlib_node_registration_t dns46_reply_node;
extern vlib_node_registration_t dns_resolver_node;
#define foreach_dns46_reply_error \
_(PROCESSED, "DNS reply pkts processed") \
_(NO_ELT, "No DNS pool element") \
_(FORMAT_ERROR, "DNS format errors") \
_(TEST_DROP, "DNS reply pkt dropped for test purposes")
typedef enum
{
#define _(sym,str) DNS46_REPLY_ERROR_##sym,
foreach_dns46_reply_error
#undef _
DNS46_REPLY_N_ERROR,
} dns46_reply_error_t;
void vnet_send_dns_request (dns_main_t * dm, dns_cache_entry_t * ep);
int vnet_dns_cname_indirection_nolock (dns_main_t * dm,
dns_cache_entry_t * ep, u8 * reply);
int vnet_dns_delete_entry_by_index_nolock (dns_main_t * dm, u32 index);
format_function_t format_dns_reply;
static inline void
dns_cache_lock (dns_main_t * dm)
{
if (dm->cache_lock)
{
while (__sync_lock_test_and_set (dm->cache_lock, 1))
;
}
}
static inline void
dns_cache_unlock (dns_main_t * dm)
{
if (dm->cache_lock)
{
CLIB_MEMORY_BARRIER ();
*dm->cache_lock = 0;
}
}
#endif /* included_dns_h */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
+154
View File
@@ -0,0 +1,154 @@
/*
* Copyright (c) 2015 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.
*/
#ifndef included_dns_packet_h
#define included_dns_packet_h
/**
* DNS packet header format
*/
/* *INDENT-OFF* */
typedef CLIB_PACKED (struct {
u16 id; /**< transaction ID */
u16 flags; /**< flags */
u16 qdcount; /**< number of questions */
u16 anscount; /**< number of answers */
u16 nscount; /**< number of name servers */
u16 arcount; /**< number of additional records */
}) dns_header_t;
/* *INDENT-ON* */
#define DNS_RCODE_MASK (0xf)
#define DNS_RCODE_NO_ERROR 0
#define DNS_RCODE_FORMAT_ERROR 1
#define DNS_RCODE_SERVER_FAILURE 2
#define DNS_RCODE_NAME_ERROR 3
#define DNS_RCODE_NOT_IMPLEMENTED 4
#define DNS_RCODE_REFUSED 5
#define DNS_RA (1<<7) /**< recursion available */
#define DNS_RD (1<<8) /**< recursion desired */
#define DNS_TC (1<<9) /**< truncation */
#define DNS_AA (1<<10) /**< authoritative answer */
#define DNS_OPCODE_MASK (0xf<<11) /**< opcode mask */
#define DNS_OPCODE_QUERY (0<<11) /**< standard query */
#define DNS_OPCODE_IQUERY (1<<11) /**< inverse query (deprecated) */
#define DNS_OPCODE_STATUS (2<<11) /**< server status */
#define DNS_QR (1<<15) /**< query=0, response=1 */
/*
* Note: in DNS-land, www.foobar.com is encoded as three "labels,"
* each of which amount to a 1 octet length followed by up to 63
* octets of name. Don't forget to add a "null root label" after the last
* real one, or the poor slob trying to parse the name will have
* no chance whatsoever.
*
* All RRs have the same top level format shown below:
*
* 1 1 1 1 1 1
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | |
* / /
* / NAME /
* | |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | TYPE |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | CLASS |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | TTL |
* | |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | RDLENGTH |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
* / RDATA /
* / /
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*
*
* DNS "questions" have the following format:
*
* 1 1 1 1 1 1
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | |
* / QNAME /
* / /
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | QTYPE |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | QCLASS |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*/
/**
* DNS "question" fixed header.
*/
/* *INDENT-OFF* */
typedef CLIB_PACKED (struct {
u16 type; /**< record type requested */
u16 class; /**< class, 1 = internet */
}) dns_query_t;
/* *INDENT-ON* */
/**
* DNS RR fixed header.
*/
/* *INDENT-OFF* */
typedef CLIB_PACKED (struct {
u16 type; /**< record type */
u16 class; /**< class, 1 = internet */
u32 ttl; /**< time to live, in seconds */
u16 rdlength;
/**< length of r */
u8 rdata[0];
}) dns_rr_t;
/* *INDENT-ON* */
/*
* There are quite a number of DNS record types
* Feel free to add as needed
*/
#define foreach_dns_type \
_(A, 1) /**< ip4 host address */ \
_(AAAA, 28) /**< ip6 host address */ \
_(ALL, 255) /**< all available data */ \
_(TEXT, 16) /**< a text string */ \
_(NAMESERVER, 2) /**< a nameserver */ \
_(CNAME, 5) /**< a CNAME (alias) */ \
_(MAIL_EXCHANGE, 15) /**< a mail exchange */
typedef enum
{
#define _(name,value) DNS_TYPE_##name = value,
foreach_dns_type
#undef _
} dns_type_t;
#define DNS_CLASS_IN 1 /**< The Internet */
#endif /* included_dns_packet_h */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
+214
View File
@@ -0,0 +1,214 @@
/*
* 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_reply_node;
typedef struct
{
u32 pool_index;
u32 disposition;
} dns46_reply_trace_t;
/* packet trace format function */
static u8 *
format_dns46_reply_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_reply_trace_t *t = va_arg (*args, dns46_reply_trace_t *);
s = format (s, "DNS46_REPLY: pool index %d, disposition %d",
t->pool_index, t->disposition);
return s;
}
vlib_node_registration_t dns46_reply_node;
static char *dns46_reply_error_strings[] = {
#define _(sym,string) string,
foreach_dns46_reply_error
#undef _
};
typedef enum
{
DNS46_REPLY_NEXT_DROP,
DNS46_REPLY_N_NEXT,
} dns46_reply_next_t;
static uword
dns46_reply_node_fn (vlib_main_t * vm,
vlib_node_runtime_t * node, vlib_frame_t * frame)
{
u32 n_left_from, *from, *to_next;
dns46_reply_next_t next_index;
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_REPLY_NEXT_INTERFACE_OUTPUT;
u32 next1 = DNS46_REPLY_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_reply_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_reply_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_REPLY_NEXT_DROP;
dns_header_t *d0;
u32 pool_index0;
u32 error0;
u8 *resp0 = 0;
/* 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);
pool_index0 = clib_host_to_net_u16 (d0->id);
/* Save the reply */
vec_validate (resp0, vlib_buffer_length_in_chain (vm, b0) - 1);
clib_memcpy (resp0, d0, vlib_buffer_length_in_chain (vm, b0));
/*
* Deal with everything in process ctx on the main thread
*/
vlib_process_signal_event_mt (vm, dns_resolver_node.index,
DNS_RESOLVER_EVENT_RESOLVED,
(uword) resp0);
error0 = DNS46_REPLY_ERROR_PROCESSED;
b0->error = node->errors[error0];
if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
&& (b0->flags & VLIB_BUFFER_IS_TRACED)))
{
dns46_reply_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;
}
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",}
,};
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
+243
View File
@@ -0,0 +1,243 @@
/*
* 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 <vlibapi/api.h>
#include <vlibmemory/api.h>
#include <vlib/vlib.h>
#include <vnet/vnet.h>
#include <vnet/vnet_msg_enum.h>
#define vl_typedefs /* define message structures */
#include <vnet/vnet_all_api_h.h>
#undef vl_typedefs
#define vl_endianfun /* define message structures */
#include <vnet/vnet_all_api_h.h>
#undef vl_endianfun
/* instantiate all the print functions we know about */
#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
#define vl_printfun
#include <vnet/vnet_all_api_h.h>
#undef vl_printfun
#include <vlibapi/api_helper_macros.h>
vlib_node_registration_t dns_resolver_node;
extern int
vnet_dns_response_to_reply (u8 * response,
vl_api_dns_resolve_name_reply_t * rmp,
u32 * min_ttlp);
static void
resolve_event (dns_main_t * dm, f64 now, u8 * reply)
{
vlib_main_t *vm = dm->vlib_main;
dns_header_t *d;
u32 pool_index;
dns_cache_entry_t *ep;
u32 min_ttl;
u16 flags;
u16 rcode;
int i;
int rv = 0;
d = (dns_header_t *) reply;
flags = clib_net_to_host_u16 (d->flags);
rcode = flags & DNS_RCODE_MASK;
/* $$$ u16 limits cache to 65K entries, fix later multiple dst ports */
pool_index = clib_net_to_host_u16 (d->id);
dns_cache_lock (dm);
if (pool_is_free_index (dm->entries, pool_index))
{
vec_free (reply);
vlib_node_increment_counter (vm, dns46_reply_node.index,
DNS46_REPLY_ERROR_NO_ELT, 1);
dns_cache_unlock (dm);
return;
}
ep = pool_elt_at_index (dm->entries, pool_index);
if (ep->dns_response)
vec_free (ep->dns_response);
/* Handle [sic] recursion AKA CNAME indirection */
if (vnet_dns_cname_indirection_nolock (dm, ep, reply))
{
dns_cache_unlock (dm);
return;
}
/* Save the response */
ep->dns_response = reply;
/* Pick some sensible default. */
ep->expiration_time = now + 600.0;
if (vec_len (ep->dns_response))
ep->flags |= DNS_CACHE_ENTRY_FLAG_VALID;
/* Most likely, send 1 message */
for (i = 0; i < vec_len (ep->api_clients_to_notify); i++)
{
vl_api_registration_t *regp;
vl_api_dns_resolve_name_reply_t *rmp;
regp = vl_api_client_index_to_registration
(ep->api_clients_to_notify[i]);
if (regp == 0)
continue;
rmp = vl_msg_api_alloc (sizeof (*rmp) + vec_len (ep->dns_response));
rmp->_vl_msg_id = clib_host_to_net_u16 (VL_API_DNS_RESOLVE_NAME_REPLY);
rmp->context = ep->api_client_contexts[i];
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);
}
vec_free (ep->api_clients_to_notify);
vec_free (ep->api_client_contexts);
/* $$$ Add ip4/ip6 reply code */
for (i = 0; i < vec_len (dm->unresolved_entries); i++)
{
if (dm->unresolved_entries[i] == pool_index)
{
vec_delete (dm->unresolved_entries, 1, i);
goto found;
}
}
clib_warning ("pool index %d AWOL from unresolved vector", pool_index);
found:
/* Deal with bogus names, server issues, etc. */
switch (rcode)
{
default:
case DNS_RCODE_NO_ERROR:
break;
case DNS_RCODE_SERVER_FAILURE:
case DNS_RCODE_NOT_IMPLEMENTED:
case DNS_RCODE_REFUSED:
if (ep->server_af == 0)
clib_warning ("name server %U backfire",
format_ip4_address,
dm->ip4_name_servers + ep->server_rotor);
else
clib_warning ("name server %U backfire",
format_ip6_address,
dm->ip6_name_servers + ep->server_rotor);
/* FALLTHROUGH */
case DNS_RCODE_NAME_ERROR:
case DNS_RCODE_FORMAT_ERROR:
/* remove trash from the cache... */
vnet_dns_delete_entry_by_index_nolock (dm, ep - dm->entries);
break;
}
dns_cache_unlock (dm);
return;
}
static void
retry_scan (dns_main_t * dm, f64 now)
{
int i;
dns_cache_entry_t *ep;
for (i = 0; i < vec_len (dm->unresolved_entries); i++)
{
dns_cache_lock (dm);
ep = pool_elt_at_index (dm->entries, dm->unresolved_entries[i]);
ASSERT ((ep->flags & DNS_CACHE_ENTRY_FLAG_VALID) == 0);
vnet_send_dns_request (dm, ep);
dns_cache_unlock (dm);
}
}
static uword
dns_resolver_process (vlib_main_t * vm,
vlib_node_runtime_t * rt, vlib_frame_t * f)
{
dns_main_t *dm = &dns_main;
f64 now;
f64 timeout = 1000.0;
uword *event_data = 0;
uword event_type;
int i;
while (1)
{
vlib_process_wait_for_event_or_clock (vm, timeout);
now = vlib_time_now (vm);
event_type = vlib_process_get_events (vm, (uword **) & event_data);
switch (event_type)
{
/* Send one of these when a resolution is pending */
case DNS_RESOLVER_EVENT_PENDING:
timeout = 2.0;
break;
case DNS_RESOLVER_EVENT_RESOLVED:
for (i = 0; i < vec_len (event_data); i++)
resolve_event (dm, now, (u8 *) event_data[i]);
break;
case ~0: /* timeout */
retry_scan (dm, now);
break;
}
vec_reset_length (event_data);
/* No work? Back to slow timeout mode... */
if (vec_len (dm->unresolved_entries) == 0)
timeout = 1000.0;
}
return 0; /* or not */
}
/* *INDENT-OFF* */
VLIB_REGISTER_NODE (dns_resolver_node) =
{
.function = dns_resolver_process,
.type = VLIB_NODE_TYPE_PROCESS,
.name = "dns-resolver-process",
};
/* *INDENT-ON* */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
+3
View File
@@ -137,6 +137,9 @@ do { \
if ((error = vlib_call_init_function (vm, flow_classify_init)))
return error;
if ((error = vlib_call_init_function (vm, dns_init)))
return error;
return error;
}
+6 -2
View File
@@ -78,6 +78,7 @@ typedef enum
} udp_error_t;
#define foreach_udp4_dst_port \
_ (53, dns) \
_ (67, dhcp_to_server) \
_ (68, dhcp_to_client) \
_ (500, ikev2) \
@@ -91,10 +92,12 @@ _ (4789, vxlan) \
_ (4789, vxlan6) \
_ (4790, VXLAN_GPE) \
_ (6633, vpath_3) \
_ (6081, geneve)
_ (6081, geneve) \
_ (53053, dns_reply)
#define foreach_udp6_dst_port \
_ (53, dns6) \
_ (547, dhcpv6_to_server) \
_ (546, dhcpv6_to_client) \
_ (2152, GTPU6) \
@@ -104,7 +107,8 @@ _ (4341, lisp_gpe6) \
_ (4342, lisp_cp6) \
_ (4790, VXLAN6_GPE) \
_ (6633, vpath6_3) \
_ (6081, geneve6)
_ (6081, geneve6) \
_ (53053, dns_reply6)
typedef enum
{
+1
View File
@@ -60,6 +60,7 @@
#include <vnet/policer/policer.api.h>
#include <vnet/ethernet/p2p_ethernet.api.h>
#include <vnet/tcp/tcp.api.h>
#include <vnet/dns/dns.api.h>
/*
* fd.io coding-style-patch-verification: ON
+43 -1
View File
@@ -3127,6 +3127,16 @@ static void *vl_api_lldp_config_t_print
s = format (s, "system_name %s ", mp->system_name);
s = format (s, "tx_hold %d ", ntohl (mp->tx_hold));
s = format (s, "tx_interval %d ", ntohl (mp->tx_interval));
FINISH;
}
static void *vl_api_dns_enable_disable_t_print
(vl_api_dns_enable_disable_t * mp, void *handle)
{
u8 *s;
s = format (0, "SCRIPT: dns_enable_disable ");
s = format (s, "%s ", mp->enable ? "enable" : "disable");
FINISH;
}
@@ -3160,6 +3170,35 @@ static void *vl_api_sw_interface_set_lldp_t_print
FINISH;
}
static void *vl_api_dns_name_server_add_del_t_print
(vl_api_dns_name_server_add_del_t * mp, void *handle)
{
u8 *s;
s = format (0, "SCRIPT: dns_name_server_add_del ");
if (mp->is_ip6)
s = format (s, "%U ", format_ip6_address,
(ip6_address_t *) mp->server_address);
else
s = format (s, "%U ", format_ip4_address,
(ip4_address_t *) mp->server_address);
if (mp->is_add == 0)
s = format (s, "del ");
FINISH;
}
static void *vl_api_dns_resolve_name_t_print
(vl_api_dns_resolve_name_t * mp, void *handle)
{
u8 *s;
s = format (0, "SCRIPT: dns_resolve_name ");
s = format (s, "%s ", mp->name);
FINISH;
}
#define foreach_custom_print_no_arg_function \
_(lisp_eid_table_vni_dump) \
_(lisp_map_resolver_dump) \
@@ -3352,7 +3391,10 @@ _(P2P_ETHERNET_DEL, p2p_ethernet_del) \
_(TCP_CONFIGURE_SRC_ADDRESSES, tcp_configure_src_addresses) \
_(APP_NAMESPACE_ADD_DEL, app_namespace_add_del) \
_(LLDP_CONFIG, lldp_config) \
_(SW_INTERFACE_SET_LLDP, sw_interface_set_lldp)
_(SW_INTERFACE_SET_LLDP, sw_interface_set_lldp) \
_(DNS_ENABLE_DISABLE, dns_enable_disable) \
_(DNS_NAME_SERVER_ADD_DEL, dns_name_server_add_del) \
_(DNS_RESOLVE_NAME, dns_resolve_name)
void
vl_msg_api_custom_dump_configure (api_main_t * am)
{