FD.io VPP  v21.01.1
Vector Packet Processing
ip6_neighbor.c
Go to the documentation of this file.
1 /*
2  * ip/ip6_neighbor.c: IP6 neighbor handling
3  *
4  * Copyright (c) 2010 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
19 #include <vnet/util/throttle.h>
20 #include <vnet/fib/fib_sas.h>
21 
22 /** ND throttling */
24 
25 void
26 ip6_neighbor_probe_dst (u32 sw_if_index, const ip6_address_t * dst)
27 {
28  ip6_address_t src;
29 
30  if (fib_sas6_get (sw_if_index, dst, &src))
32  sw_if_index, &src, dst);
33 }
34 
35 void
37  vnet_main_t * vnm,
38  u32 sw_if_index, const ip6_address_t * addr)
39 {
40  vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
41  ip6_main_t *i6m = &ip6_main;
42  u8 *rewrite, rewrite_len;
43  u8 dst_address[6];
44 
45  if (NULL == addr)
46  addr = ip6_interface_first_address (i6m, sw_if_index);
47 
48  if (addr)
49  {
51  ("Sending unsolicitated NA IP6 address %U on sw_if_idex %d",
52  format_ip6_address, addr, sw_if_index);
53 
54  /* Form unsolicited neighbor advertisement packet from NS pkt template */
55  int bogus_length;
56  u32 bi = 0;
57  icmp6_neighbor_solicitation_header_t *h =
59  &ip6_neighbor_packet_template,
60  &bi);
61  if (!h)
62  return;
63 
64  ip6_set_reserved_multicast_address (&h->ip.dst_address,
65  IP6_MULTICAST_SCOPE_link_local,
66  IP6_MULTICAST_GROUP_ID_all_hosts);
67  h->ip.src_address = addr[0];
68  h->neighbor.icmp.type = ICMP6_neighbor_advertisement;
69  h->neighbor.target_address = addr[0];
70  h->neighbor.advertisement_flags = clib_host_to_net_u32
72  h->link_layer_option.header.type =
73  ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
74  clib_memcpy (h->link_layer_option.ethernet_address,
75  hi->hw_address, vec_len (hi->hw_address));
76  h->neighbor.icmp.checksum =
77  ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
78  ASSERT (bogus_length == 0);
79 
80  /* Setup MAC header with IP6 Etype and mcast DMAC */
81  vlib_buffer_t *b = vlib_get_buffer (vm, bi);
82  ip6_multicast_ethernet_address (dst_address,
83  IP6_MULTICAST_GROUP_ID_all_hosts);
84  rewrite =
85  ethernet_build_rewrite (vnm, sw_if_index, VNET_LINK_IP6, dst_address);
86  rewrite_len = vec_len (rewrite);
87  vlib_buffer_advance (b, -rewrite_len);
89  clib_memcpy (e->dst_address, rewrite, rewrite_len);
90  vec_free (rewrite);
91 
92  /* Send unsolicited ND advertisement packet out the specified interface */
93  vnet_buffer (b)->sw_if_index[VLIB_RX] =
94  vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
96  u32 *to_next = vlib_frame_vector_args (f);
97  to_next[0] = bi;
98  f->n_vectors = 1;
100  }
101 }
102 
103 typedef enum
104 {
109 
110 typedef enum
111 {
117 
118 static uword
121  vlib_frame_t * frame, int is_glean)
122 {
123  vnet_main_t *vnm = vnet_get_main ();
124  u32 *from, *to_next_drop;
125  uword n_left_from, n_left_to_next_drop;
126  u64 seed;
127  u32 thread_index = vm->thread_index;
128 
129  if (node->flags & VLIB_NODE_FLAG_TRACE)
130  ip6_forward_next_trace (vm, node, frame, VLIB_TX);
131 
132  seed = throttle_seed (&nd_throttle, thread_index, vlib_time_now (vm));
133 
134  from = vlib_frame_vector_args (frame);
135  n_left_from = frame->n_vectors;
136 
137  while (n_left_from > 0)
138  {
140  to_next_drop, n_left_to_next_drop);
141 
142  while (n_left_from > 0 && n_left_to_next_drop > 0)
143  {
144  u32 pi0, adj_index0, sw_if_index0, drop0, r0;
145  vnet_hw_interface_t *hw_if0;
146  vlib_buffer_t *p0, *b0;
147  ip_adjacency_t *adj0;
148  ip6_address_t src;
149  ip6_header_t *ip0;
150 
151  pi0 = from[0];
152 
153  p0 = vlib_get_buffer (vm, pi0);
154 
155  adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
156 
157  ip0 = vlib_buffer_get_current (p0);
158 
159  adj0 = adj_get (adj_index0);
160 
161  if (!is_glean)
162  {
163  ip0->dst_address.as_u64[0] =
164  adj0->sub_type.nbr.next_hop.ip6.as_u64[0];
165  ip0->dst_address.as_u64[1] =
166  adj0->sub_type.nbr.next_hop.ip6.as_u64[1];
167  }
168 
169  sw_if_index0 = adj0->rewrite_header.sw_if_index;
170  vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
171 
172  /* combine the address and interface for a hash */
173  r0 = ip6_address_hash_to_u64 (&ip0->dst_address) ^ sw_if_index0;
174 
175  drop0 = throttle_check (&nd_throttle, thread_index, r0, seed);
176 
177  from += 1;
178  n_left_from -= 1;
179  to_next_drop[0] = pi0;
180  to_next_drop += 1;
181  n_left_to_next_drop -= 1;
182 
183  hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
184 
185  /* If the interface is link-down, drop the pkt */
186  if (!(hw_if0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
187  drop0 = 1;
188 
189  if (!ip6_link_is_enabled (sw_if_index0))
190  drop0 = 1;
191 
192  /*
193  * the adj has been updated to a rewrite but the node the DPO that got
194  * us here hasn't - yet. no big deal. we'll drop while we wait.
195  */
197  drop0 = 1;
198 
199  if (drop0)
200  {
201  p0->error = node->errors[IP6_NBR_ERROR_DROP];
202  continue;
203  }
204 
205  /*
206  * Choose source address based on destination lookup
207  * adjacency.
208  */
209  if (!fib_sas6_get (sw_if_index0, &ip0->dst_address, &src))
210  {
211  /* There is no address on the interface */
213  continue;
214  }
215 
216  b0 = ip6_neighbor_probe (vm, vnm, sw_if_index0,
217  &src, &ip0->dst_address);
218 
219  if (PREDICT_TRUE (NULL != b0))
220  {
221  clib_memcpy_fast (b0->opaque2, p0->opaque2,
222  sizeof (p0->opaque2));
223  b0->flags |= p0->flags & VLIB_BUFFER_IS_TRACED;
224  b0->trace_handle = p0->trace_handle;
226  }
227  else
228  {
229  /* There is no address on the interface */
231  continue;
232  }
233  }
234 
235  vlib_put_next_frame (vm, node, IP6_NBR_NEXT_DROP, n_left_to_next_drop);
236  }
237 
238  return frame->n_vectors;
239 }
240 
241 static uword
244 {
245  return (ip6_discover_neighbor_inline (vm, node, frame, 0));
246 }
247 
248 static uword
250 {
251  return (ip6_discover_neighbor_inline (vm, node, frame, 1));
252 }
253 
255  [IP6_NBR_ERROR_DROP] = "address overflow drops",
256  [IP6_NBR_ERROR_REQUEST_SENT] = "neighbor solicitations sent",
257  [IP6_NBR_ERROR_NO_SOURCE_ADDRESS] = "no source address for ND solicitation",
258  [IP6_NBR_ERROR_NO_BUFFERS] = "no buffers",
259 };
260 
261 /* *INDENT-OFF* */
263 {
264  .function = ip6_glean,
265  .name = "ip6-glean",
266  .vector_size = sizeof (u32),
267  .format_trace = format_ip6_forward_next_trace,
269  .error_strings = ip6_discover_neighbor_error_strings,
270  .n_next_nodes = IP6_NBR_N_NEXT,
271  .next_nodes =
272  {
273  [IP6_NBR_NEXT_DROP] = "ip6-drop",
274  [IP6_NBR_NEXT_REPLY_TX] = "ip6-rewrite-mcast",
275  },
276 };
278 {
279  .function = ip6_discover_neighbor,
280  .name = "ip6-discover-neighbor",
281  .vector_size = sizeof (u32),
282  .format_trace = format_ip6_forward_next_trace,
284  .error_strings = ip6_discover_neighbor_error_strings,
285  .n_next_nodes = IP6_NBR_N_NEXT,
286  .next_nodes =
287  {
288  [IP6_NBR_NEXT_DROP] = "ip6-drop",
289  [IP6_NBR_NEXT_REPLY_TX] = "ip6-rewrite-mcast",
290  },
291 };
292 /* *INDENT-ON* */
293 
294 /* Template used to generate IP6 neighbor solicitation packets. */
296 
297 static clib_error_t *
299 {
300  icmp6_neighbor_solicitation_header_t p;
301 
302  clib_memset (&p, 0, sizeof (p));
303 
304  p.ip.ip_version_traffic_class_and_flow_label =
305  clib_host_to_net_u32 (0x6 << 28);
306  p.ip.payload_length =
307  clib_host_to_net_u16 (sizeof (p) -
309  (icmp6_neighbor_solicitation_header_t, neighbor));
310  p.ip.protocol = IP_PROTOCOL_ICMP6;
311  p.ip.hop_limit = 255;
312  ip6_set_solicited_node_multicast_address (&p.ip.dst_address, 0);
313 
314  p.neighbor.icmp.type = ICMP6_neighbor_solicitation;
315 
316  p.link_layer_option.header.type =
317  ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
318  p.link_layer_option.header.n_data_u64s =
319  sizeof (p.link_layer_option) / sizeof (u64);
320 
322  &ip6_neighbor_packet_template, &p, sizeof (p),
323  /* alloc chunk size */ 8,
324  "ip6 neighbor discovery");
325 
326  return NULL;
327 }
328 
330 
331 static clib_error_t *
333 {
335 
336  throttle_init (&nd_throttle, tm->n_vlib_mains, 1e-3);
337 
338  return 0;
339 }
340 
342 
343 /*
344  * fd.io coding-style-patch-verification: ON
345  *
346  * Local Variables:
347  * eval: (c-set-style "gnu")
348  * End:
349  */
u32 opaque2[14]
Definition: buffer.h:170
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:124
static vlib_buffer_t * ip6_neighbor_probe(vlib_main_t *vm, vnet_main_t *vnm, u32 sw_if_index, const ip6_address_t *src, const ip6_address_t *dst)
Definition: ip6_neighbor.h:41
ip6_discover_neighbor_next_t
Definition: ip6_neighbor.c:103
static clib_error_t * ip6_neighbor_init(vlib_main_t *vm)
Definition: ip6_neighbor.c:298
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
#define VLIB_MAIN_LOOP_ENTER_FUNCTION(x)
Definition: init.h:176
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
#define PREDICT_TRUE(x)
Definition: clib.h:122
unsigned long u64
Definition: types.h:89
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:334
IP unicast adjacency.
Definition: adj.h:235
u32 thread_index
Definition: main.h:250
static uword ip6_discover_neighbor_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int is_glean)
Definition: ip6_neighbor.c:119
This packet is to be rewritten and forwarded to the next processing node.
Definition: adj.h:73
void throttle_init(throttle_t *t, u32 n_threads, f64 time)
Definition: throttle.c:19
ip6_address_t * ip6_interface_first_address(ip6_main_t *im, u32 sw_if_index)
get first IPv6 interface address
Definition: ip6_forward.c:279
vl_api_address_t src
Definition: gre.api:54
#define STRUCT_OFFSET_OF(t, f)
Definition: clib.h:70
vlib_packet_template_t ip6_neighbor_packet_template
Definition: ip6_neighbor.c:295
vlib_main_t * vm
Definition: in2out_ed.c:1580
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:470
vhost_vring_addr_t addr
Definition: vhost_user.h:111
unsigned char u8
Definition: types.h:56
#define clib_memcpy(d, s, n)
Definition: string.h:180
static ip_adjacency_t * adj_get(adj_index_t adj_index)
Get a pointer to an adjacency object from its index.
Definition: adj.h:467
static u64 ip6_address_hash_to_u64(const ip6_address_t *a)
Definition: ip6_packet.h:289
struct ip_adjacency_t_::@161::@162 nbr
IP_LOOKUP_NEXT_ARP/IP_LOOKUP_NEXT_REWRITE.
void * vlib_packet_template_get_packet(vlib_main_t *vm, vlib_packet_template_t *t, u32 *bi_result)
Definition: buffer.c:400
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
static uword ip6_glean(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_neighbor.c:249
#define ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE
u8 dst_address[6]
Definition: packet.h:55
vnet_hw_interface_flags_t flags
Definition: interface.h:538
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:182
bool fib_sas6_get(u32 sw_if_index, const ip6_address_t *dst, ip6_address_t *src)
Get an IPv6 Source address to use in a packet being sent out an interface.
Definition: fib_sas.c:87
const cJSON *const b
Definition: cJSON.h:255
unsigned int u32
Definition: types.h:88
static clib_error_t * ip6_nd_main_loop_enter(vlib_main_t *vm)
Definition: ip6_neighbor.c:332
void ip6_neighbor_advertise(vlib_main_t *vm, vnet_main_t *vnm, u32 sw_if_index, const ip6_address_t *addr)
Definition: ip6_neighbor.c:36
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
void vlib_packet_template_init(vlib_main_t *vm, vlib_packet_template_t *t, void *packet_data, uword n_packet_data_bytes, uword min_n_buffers_each_alloc, char *fmt,...)
Definition: buffer.c:378
static char * ip6_discover_neighbor_error_strings[]
Definition: ip6_neighbor.c:254
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:216
vec_header_t h
Definition: buffer.c:322
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:233
u32 trace_handle
Specifies trace buffer handle if VLIB_PACKET_IS_TRACED flag is set.
Definition: buffer.h:163
static u64 throttle_seed(throttle_t *t, u32 thread_index, f64 time_now)
Definition: throttle.h:41
ip6_discover_neighbor_error_t
Definition: ip6_neighbor.c:110
ip6_main_t ip6_main
Definition: ip6_forward.c:2785
vl_api_address_t dst
Definition: gre.api:55
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:391
A throttle Used in the data plane to decide if a given hash should be throttled, i.e.
Definition: throttle.h:28
vlib_thread_main_t vlib_thread_main
Definition: threads.c:35
static uword ip6_discover_neighbor(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_neighbor.c:242
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:170
u16 n_vectors
Definition: node.h:397
format_function_t format_ip6_address
Definition: format.h:91
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:380
#define clib_warning(format, args...)
Definition: error.h:59
#define ARRAY_LEN(x)
Definition: clib.h:67
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:483
void ip6_neighbor_probe_dst(u32 sw_if_index, const ip6_address_t *dst)
Definition: ip6_neighbor.c:26
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1580
u16 ip6_tcp_udp_icmp_compute_checksum(vlib_main_t *vm, vlib_buffer_t *p0, ip6_header_t *ip0, int *bogus_lengthp)
Definition: ip6_forward.c:1099
#define ASSERT(truth)
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:252
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
vl_api_ip4_address_t hi
Definition: arp.api:37
union ip_adjacency_t_::@161 sub_type
Definition: defs.h:47
static throttle_t nd_throttle
ND throttling.
Definition: ip6_neighbor.c:23
static void ip6_set_solicited_node_multicast_address(ip6_address_t *a, u32 id)
Definition: ip6_packet.h:144
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
ip_lookup_next_t lookup_next_index
Next hop after ip4-lookup.
Definition: adj.h:337
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1581
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:297
u8 * ethernet_build_rewrite(vnet_main_t *vnm, u32 sw_if_index, vnet_link_t link_type, const void *dst_address)
build a rewrite string to use for sending packets of type &#39;link_type&#39; to &#39;dst_address&#39; ...
Definition: interface.c:83
vlib_node_registration_t ip6_glean_node
(constructor) VLIB_REGISTER_NODE (ip6_glean_node)
Definition: ip6_neighbor.c:262
#define vnet_buffer(b)
Definition: buffer.h:417
vlib_node_registration_t ip6_discover_neighbor_node
(constructor) VLIB_REGISTER_NODE (ip6_discover_neighbor_node)
Definition: ip6_neighbor.c:277
void ip6_forward_next_trace(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, vlib_rx_or_tx_t which_adj_index)
Definition: ip6_forward.c:1007
u16 flags
Copy of main node flags.
Definition: node.h:501
static void ip6_multicast_ethernet_address(u8 *ethernet_address, u32 group_id)
Definition: ip6_packet.h:156
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:302
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
Definition: defs.h:46
ip6_address_t dst_address
Definition: ip6_packet.h:310
static void ip6_set_reserved_multicast_address(ip6_address_t *a, ip6_multicast_address_scope_t scope, u16 id)
Definition: ip6_packet.h:134
static int throttle_check(throttle_t *t, u32 thread_index, u64 hash, u64 seed)
Definition: throttle.h:54
u8 * format_ip6_forward_next_trace(u8 *s, va_list *args)
Definition: ip6_forward.c:952