FD.io VPP  v21.06
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 VLIB_REGISTER_LOG_CLASS (ip6_neighbor_log, static) = {
26  .class_name = "ip6",
27  .subclass_name = "neighbor",
28 };
29 
30 #define log_debug(fmt, ...) \
31  vlib_log_debug (ip6_neighbor_log.class, fmt, __VA_ARGS__)
32 void
33 ip6_neighbor_probe_dst (u32 sw_if_index, const ip6_address_t * dst)
34 {
35  ip6_address_t src;
36 
37  if (fib_sas6_get (sw_if_index, dst, &src))
39  sw_if_index, &src, dst);
40 }
41 
42 void
44  vnet_main_t * vnm,
45  u32 sw_if_index, const ip6_address_t * addr)
46 {
47  vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
48  ip6_main_t *i6m = &ip6_main;
49  u8 *rewrite, rewrite_len;
50  u8 dst_address[6];
51 
52  if (NULL == addr)
53  addr = ip6_interface_first_address (i6m, sw_if_index);
54 
55  if (addr)
56  {
57  log_debug ("Sending unsolicitated NA IP6 address %U on sw_if_idex %d",
58  format_ip6_address, addr, sw_if_index);
59 
60  /* Form unsolicited neighbor advertisement packet from NS pkt template */
61  int bogus_length;
62  u32 bi = 0;
63  icmp6_neighbor_solicitation_header_t *h =
65  &ip6_neighbor_packet_template,
66  &bi);
67  if (!h)
68  return;
69 
70  ip6_set_reserved_multicast_address (&h->ip.dst_address,
71  IP6_MULTICAST_SCOPE_link_local,
72  IP6_MULTICAST_GROUP_ID_all_hosts);
73  h->ip.src_address = addr[0];
74  h->neighbor.icmp.type = ICMP6_neighbor_advertisement;
75  h->neighbor.target_address = addr[0];
76  h->neighbor.advertisement_flags = clib_host_to_net_u32
78  h->link_layer_option.header.type =
79  ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
80  clib_memcpy (h->link_layer_option.ethernet_address,
81  hi->hw_address, vec_len (hi->hw_address));
82  h->neighbor.icmp.checksum =
83  ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
84  ASSERT (bogus_length == 0);
85 
86  /* Setup MAC header with IP6 Etype and mcast DMAC */
87  vlib_buffer_t *b = vlib_get_buffer (vm, bi);
88  ip6_multicast_ethernet_address (dst_address,
89  IP6_MULTICAST_GROUP_ID_all_hosts);
90  rewrite =
91  ethernet_build_rewrite (vnm, sw_if_index, VNET_LINK_IP6, dst_address);
92  rewrite_len = vec_len (rewrite);
93  vlib_buffer_advance (b, -rewrite_len);
95  clib_memcpy (e->dst_address, rewrite, rewrite_len);
96  vec_free (rewrite);
97 
98  /* Send unsolicited ND advertisement packet out the specified interface */
99  vnet_buffer (b)->sw_if_index[VLIB_RX] =
100  vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
102  u32 *to_next = vlib_frame_vector_args (f);
103  to_next[0] = bi;
104  f->n_vectors = 1;
106  }
107 }
108 
109 typedef enum
110 {
115 
116 typedef enum
117 {
123 
124 static uword
127  vlib_frame_t * frame, int is_glean)
128 {
129  vnet_main_t *vnm = vnet_get_main ();
130  u32 *from, *to_next_drop;
131  uword n_left_from, n_left_to_next_drop;
132  u64 seed;
134 
135  if (node->flags & VLIB_NODE_FLAG_TRACE)
136  ip6_forward_next_trace (vm, node, frame, VLIB_TX);
137 
138  seed = throttle_seed (&nd_throttle, thread_index, vlib_time_now (vm));
139 
140  from = vlib_frame_vector_args (frame);
141  n_left_from = frame->n_vectors;
142 
143  while (n_left_from > 0)
144  {
146  to_next_drop, n_left_to_next_drop);
147 
148  while (n_left_from > 0 && n_left_to_next_drop > 0)
149  {
150  u32 pi0, adj_index0, sw_if_index0, drop0, r0;
151  vnet_hw_interface_t *hw_if0;
152  vlib_buffer_t *p0, *b0;
153  ip_adjacency_t *adj0;
154  ip6_address_t src;
155  ip6_header_t *ip0;
156 
157  pi0 = from[0];
158 
159  p0 = vlib_get_buffer (vm, pi0);
160 
161  adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
162 
163  ip0 = vlib_buffer_get_current (p0);
164 
165  adj0 = adj_get (adj_index0);
166 
167  if (!is_glean)
168  {
169  ip0->dst_address.as_u64[0] =
170  adj0->sub_type.nbr.next_hop.ip6.as_u64[0];
171  ip0->dst_address.as_u64[1] =
172  adj0->sub_type.nbr.next_hop.ip6.as_u64[1];
173  }
174 
175  sw_if_index0 = adj0->rewrite_header.sw_if_index;
176  vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
177 
178  /* combine the address and interface for a hash */
179  r0 = ip6_address_hash_to_u64 (&ip0->dst_address) ^ sw_if_index0;
180 
181  drop0 = throttle_check (&nd_throttle, thread_index, r0, seed);
182 
183  from += 1;
184  n_left_from -= 1;
185  to_next_drop[0] = pi0;
186  to_next_drop += 1;
187  n_left_to_next_drop -= 1;
188 
189  hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
190 
191  /* If the interface is link-down, drop the pkt */
192  if (!(hw_if0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
193  drop0 = 1;
194 
195  if (!ip6_link_is_enabled (sw_if_index0))
196  drop0 = 1;
197 
198  /*
199  * the adj has been updated to a rewrite but the node the DPO that got
200  * us here hasn't - yet. no big deal. we'll drop while we wait.
201  */
203  drop0 = 1;
204 
205  if (drop0)
206  {
207  p0->error = node->errors[IP6_NBR_ERROR_DROP];
208  continue;
209  }
210 
211  /*
212  * Choose source address based on destination lookup
213  * adjacency.
214  */
215  if (!fib_sas6_get (sw_if_index0, &ip0->dst_address, &src))
216  {
217  /* There is no address on the interface */
219  continue;
220  }
221 
222  b0 = ip6_neighbor_probe (vm, vnm, sw_if_index0,
223  &src, &ip0->dst_address);
224 
225  if (PREDICT_TRUE (NULL != b0))
226  {
227  clib_memcpy_fast (b0->opaque2, p0->opaque2,
228  sizeof (p0->opaque2));
229  b0->flags |= p0->flags & VLIB_BUFFER_IS_TRACED;
230  b0->trace_handle = p0->trace_handle;
232  }
233  else
234  {
235  /* There is no address on the interface */
237  continue;
238  }
239  }
240 
241  vlib_put_next_frame (vm, node, IP6_NBR_NEXT_DROP, n_left_to_next_drop);
242  }
243 
244  return frame->n_vectors;
245 }
246 
247 static uword
250 {
251  return (ip6_discover_neighbor_inline (vm, node, frame, 0));
252 }
253 
254 static uword
256 {
257  return (ip6_discover_neighbor_inline (vm, node, frame, 1));
258 }
259 
261  [IP6_NBR_ERROR_DROP] = "address overflow drops",
262  [IP6_NBR_ERROR_REQUEST_SENT] = "neighbor solicitations sent",
263  [IP6_NBR_ERROR_NO_SOURCE_ADDRESS] = "no source address for ND solicitation",
264  [IP6_NBR_ERROR_NO_BUFFERS] = "no buffers",
265 };
266 
267 /* *INDENT-OFF* */
269 {
270  .function = ip6_glean,
271  .name = "ip6-glean",
272  .vector_size = sizeof (u32),
273  .format_trace = format_ip6_forward_next_trace,
275  .error_strings = ip6_discover_neighbor_error_strings,
276  .n_next_nodes = IP6_NBR_N_NEXT,
277  .next_nodes =
278  {
279  [IP6_NBR_NEXT_DROP] = "ip6-drop",
280  [IP6_NBR_NEXT_REPLY_TX] = "ip6-rewrite-mcast",
281  },
282 };
284 {
285  .function = ip6_discover_neighbor,
286  .name = "ip6-discover-neighbor",
287  .vector_size = sizeof (u32),
288  .format_trace = format_ip6_forward_next_trace,
290  .error_strings = ip6_discover_neighbor_error_strings,
291  .n_next_nodes = IP6_NBR_N_NEXT,
292  .next_nodes =
293  {
294  [IP6_NBR_NEXT_DROP] = "ip6-drop",
295  [IP6_NBR_NEXT_REPLY_TX] = "ip6-rewrite-mcast",
296  },
297 };
298 /* *INDENT-ON* */
299 
300 /* Template used to generate IP6 neighbor solicitation packets. */
302 
303 static clib_error_t *
305 {
306  icmp6_neighbor_solicitation_header_t p;
307 
308  clib_memset (&p, 0, sizeof (p));
309 
310  p.ip.ip_version_traffic_class_and_flow_label =
311  clib_host_to_net_u32 (0x6 << 28);
312  p.ip.payload_length =
313  clib_host_to_net_u16 (sizeof (p) -
315  (icmp6_neighbor_solicitation_header_t, neighbor));
316  p.ip.protocol = IP_PROTOCOL_ICMP6;
317  p.ip.hop_limit = 255;
318  ip6_set_solicited_node_multicast_address (&p.ip.dst_address, 0);
319 
320  p.neighbor.icmp.type = ICMP6_neighbor_solicitation;
321 
322  p.link_layer_option.header.type =
323  ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
324  p.link_layer_option.header.n_data_u64s =
325  sizeof (p.link_layer_option) / sizeof (u64);
326 
328  &ip6_neighbor_packet_template, &p, sizeof (p),
329  /* alloc chunk size */ 8,
330  "ip6 neighbor discovery");
331 
332  return NULL;
333 }
334 
336 
337 static clib_error_t *
339 {
341 
342  throttle_init (&nd_throttle, tm->n_vlib_mains, 1e-3);
343 
344  return 0;
345 }
346 
348 
349 /*
350  * fd.io coding-style-patch-verification: ON
351  *
352  * Local Variables:
353  * eval: (c-set-style "gnu")
354  * End:
355  */
u32 opaque2[14]
Definition: buffer.h:179
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:133
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:109
static clib_error_t * ip6_neighbor_init(vlib_main_t *vm)
Definition: ip6_neighbor.c:304
#define VLIB_MAIN_LOOP_ENTER_FUNCTION(x)
Definition: init.h:175
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
u32 thread_index
#define PREDICT_TRUE(x)
Definition: clib.h:125
unsigned long u64
Definition: types.h:89
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:325
IP unicast adjacency.
Definition: adj.h:235
u32 thread_index
Definition: main.h:213
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:125
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
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: nat44_ei.c:3048
ip6_address_t * ip6_interface_first_address(ip6_main_t *im, u32 sw_if_index)
get first IPv6 interface address
Definition: ip6_forward.c:278
vl_api_address_t src
Definition: gre.api:54
#define STRUCT_OFFSET_OF(t, f)
Definition: clib.h:73
vlib_packet_template_t ip6_neighbor_packet_template
Definition: ip6_neighbor.c:301
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:461
vhost_vring_addr_t addr
Definition: vhost_user.h:130
unsigned char u8
Definition: types.h:56
vlib_buffer_t ** b
unsigned int u32
Definition: types.h:88
#define clib_memcpy(d, s, n)
Definition: string.h:197
vlib_frame_t * f
static ip_adjacency_t * adj_get(adj_index_t adj_index)
Get a pointer to an adjacency object from its index.
Definition: adj.h:470
static u64 ip6_address_hash_to_u64(const ip6_address_t *a)
Definition: ip6_packet.h:289
void * vlib_packet_template_get_packet(vlib_main_t *vm, vlib_packet_template_t *t, u32 *bi_result)
Definition: buffer.c:377
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:172
static uword ip6_glean(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_neighbor.c:255
#define ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE
u8 dst_address[6]
Definition: packet.h:55
vnet_hw_interface_flags_t flags
Definition: interface.h:642
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:184
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
vnet_main_t * vnet_get_main(void)
static clib_error_t * ip6_nd_main_loop_enter(vlib_main_t *vm)
Definition: ip6_neighbor.c:338
union ip_adjacency_t_::@144 sub_type
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:43
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:145
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
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:355
static char * ip6_discover_neighbor_error_strings[]
Definition: ip6_neighbor.c:260
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:218
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:257
u32 trace_handle
Specifies trace buffer handle if VLIB_PACKET_IS_TRACED flag is set.
Definition: buffer.h:172
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:116
ip6_main_t ip6_main
Definition: ip6_forward.c:2787
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
#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:395
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:36
static uword ip6_discover_neighbor(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_neighbor.c:248
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
#define log_debug(fmt,...)
Definition: ip6_neighbor.c:30
u16 n_vectors
Definition: node.h:388
format_function_t format_ip6_address
Definition: format.h:91
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:395
#define ARRAY_LEN(x)
Definition: clib.h:70
void ip6_neighbor_probe_dst(u32 sw_if_index, const ip6_address_t *dst)
Definition: ip6_neighbor.c:33
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:1098
#define ASSERT(truth)
VLIB_REGISTER_LOG_CLASS(ip6_neighbor_log, static)
vlib_put_next_frame(vm, node, next_index, 0)
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:276
static_always_inline void * clib_memcpy_fast(void *restrict dst, const void *restrict src, size_t n)
Definition: string.h:92
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:38
vl_api_ip4_address_t hi
Definition: arp.api:37
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)
vlib_main_t vlib_node_runtime_t * node
Definition: nat44_ei.c:3047
ip_lookup_next_t lookup_next_index
Next hop after ip4-lookup.
Definition: adj.h:337
VLIB buffer representation.
Definition: buffer.h:111
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:301
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:268
#define vnet_buffer(b)
Definition: buffer.h:437
vl_api_ip4_address_t dst
Definition: pnat.api:41
vlib_node_registration_t ip6_discover_neighbor_node
(constructor) VLIB_REGISTER_NODE (ip6_discover_neighbor_node)
Definition: ip6_neighbor.c:283
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:1006
u16 flags
Copy of main node flags.
Definition: node.h:492
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:292
struct ip_adjacency_t_::@144::@145 nbr
IP_LOOKUP_NEXT_ARP/IP_LOOKUP_NEXT_REWRITE.
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:111
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
rewrite
Definition: pnat.api:158
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:951