FD.io VPP  v20.01-48-g3e0dafb74
Vector Packet Processing
l2_arp_term.c
Go to the documentation of this file.
1 /*
2  * l2/l2_arp_term.c: IP v4 ARP L2 BD termination
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 
18 #include <vlibmemory/api.h>
19 
20 #include <vnet/l2/l2_arp_term.h>
21 #include <vnet/l2/l2_input.h>
22 #include <vnet/l2/feat_bitmap.h>
23 
24 #include <vnet/ip/ip4_packet.h>
26 
27 static const u8 vrrp_prefix[] = { 0x00, 0x00, 0x5E, 0x00, 0x01 };
28 
30 
31 /*
32  * ARP/ND Termination in a L2 Bridge Domain based on IP4/IP6 to MAC
33  * hash tables mac_by_ip4 and mac_by_ip6 for each BD.
34  */
35 typedef enum
36 {
41 
43 
44 typedef struct
45 {
46  u8 packet_data[64];
48 
49 #define foreach_ethernet_arp_error \
50  _ (replies_sent, "ARP replies sent") \
51  _ (l2_type_not_ethernet, "L2 type not ethernet") \
52  _ (l3_type_not_ip4, "L3 type not IP4") \
53  _ (l3_src_address_not_local, "IP4 source address not local to subnet") \
54  _ (l3_dst_address_not_local, "IP4 destination address not local to subnet") \
55  _ (l3_dst_address_unset, "IP4 destination address is unset") \
56  _ (l3_src_address_is_local, "IP4 source address matches local interface") \
57  _ (l3_src_address_learned, "ARP request IP4 source address learned") \
58  _ (replies_received, "ARP replies received") \
59  _ (opcode_not_request, "ARP opcode not request") \
60  _ (proxy_arp_replies_sent, "Proxy ARP replies sent") \
61  _ (l2_address_mismatch, "ARP hw addr does not match L2 frame src addr") \
62  _ (gratuitous_arp, "ARP probe or announcement dropped") \
63  _ (interface_no_table, "Interface is not mapped to an IP table") \
64  _ (interface_not_ip_enabled, "Interface is not IP enabled") \
65  _ (unnumbered_mismatch, "RX interface is unnumbered to different subnet") \
66 
67 typedef enum
68 {
69 #define _(sym,string) ETHERNET_ARP_ERROR_##sym,
71 #undef _
74 
75 static char *ethernet_arp_error_strings[] = {
76 #define _(sym,string) string,
78 #undef _
79 };
80 
81 static u8 *
82 format_arp_term_input_trace (u8 * s, va_list * va)
83 {
84  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
85  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
87 
88  /* arp-term trace data saved is either arp or ip6/icmp6 packet:
89  - for arp, the 1st 16-bit field is hw type of value of 0x0001.
90  - for ip6, the first nibble has value of 6. */
91  s = format (s, "%U", t->packet_data[0] == 0 ?
93  t->packet_data, sizeof (t->packet_data));
94 
95  return s;
96 }
97 
98 void
100 {
102 
103  l2am->publish = on;
104 }
105 
106 static int
108 {
110 
111  vec_add1 (l2am->publish_events, *ctx);
112 
116 
117  return 0;
118 }
119 
120 static inline void
122  const ethernet_arp_ip4_over_ethernet_address_t * a)
123 {
125 
126  if (!l2am->publish)
127  return;
128 
131  .type = IP46_TYPE_IP4,
132  .ip.ip4 = a->ip4,
133  .mac = a->mac,
134  };
135 
137  sizeof (args));
138 }
139 
140 static inline void
142  const ip6_address_t * addr,
143  const mac_address_t * mac)
144 {
146 
147  if (!l2am->publish)
148  return;
149 
152  .type = IP46_TYPE_IP6,
153  .ip.ip6 = *addr,
154  .mac = *mac,
155  };
156 
158  sizeof (args));
159 }
160 
161 static inline int
164  vlib_buffer_t * p0,
165  ethernet_header_t * eth,
166  ip6_header_t * ip, u32 sw_if_index, u16 bd_index)
167 {
168  icmp6_neighbor_solicitation_or_advertisement_header_t *ndh;
170 
171  mac_address_from_bytes (&mac, eth->src_address);
172  ndh = ip6_next_header (ip);
173  if (ndh->icmp.type != ICMP6_neighbor_solicitation &&
174  ndh->icmp.type != ICMP6_neighbor_advertisement)
175  return 0;
176 
177  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
178  (p0->flags & VLIB_BUFFER_IS_TRACED)))
179  {
180  u8 *t0 = vlib_add_trace (vm, node, p0,
181  sizeof (icmp6_input_trace_t));
182  clib_memcpy (t0, ip, sizeof (icmp6_input_trace_t));
183  }
184 
185  /* Check if anyone want ND events for L2 BDs */
187  {
188  l2_arp_term_publish_v6_dp (sw_if_index, &ip->src_address, &mac);
189  }
190 
191  /* Check if MAC entry exsist for solicited target IP */
192  if (ndh->icmp.type == ICMP6_neighbor_solicitation)
193  {
194  icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *opt;
195  l2_bridge_domain_t *bd_config;
196  u8 *macp;
197 
198  opt = (void *) (ndh + 1);
199  if ((opt->header.type !=
200  ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address) ||
201  (opt->header.n_data_u64s != 1))
202  return 0; /* source link layer address option not present */
203 
204  bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
205  macp =
206  (u8 *) hash_get_mem (bd_config->mac_by_ip6, &ndh->target_address);
207  if (macp)
208  { /* found ip-mac entry, generate eighbor advertisement response */
209  int bogus_length;
210  vlib_node_runtime_t *error_node =
212  ip->dst_address = ip->src_address;
213  ip->src_address = ndh->target_address;
214  ip->hop_limit = 255;
215  opt->header.type =
216  ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
217  clib_memcpy (opt->ethernet_address, macp, 6);
218  ndh->icmp.type = ICMP6_neighbor_advertisement;
219  ndh->advertisement_flags = clib_host_to_net_u32
222  ndh->icmp.checksum = 0;
223  ndh->icmp.checksum =
224  ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip, &bogus_length);
225  clib_memcpy (eth->dst_address, eth->src_address, 6);
226  clib_memcpy (eth->src_address, macp, 6);
227  vlib_error_count (vm, error_node->node_index,
228  ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_TX, 1);
229  return 1;
230  }
231  }
232 
233  return 0;
234 
235 }
236 
237 static uword
240 {
241  l2input_main_t *l2im = &l2input_main;
242  u32 n_left_from, next_index, *from, *to_next;
243  u32 n_replies_sent = 0;
244  u16 last_bd_index = ~0;
245  l2_bridge_domain_t *last_bd_config = 0;
246  l2_input_config_t *cfg0;
247 
248  from = vlib_frame_vector_args (frame);
249  n_left_from = frame->n_vectors;
250  next_index = node->cached_next_index;
251 
252  while (n_left_from > 0)
253  {
254  u32 n_left_to_next;
255 
256  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
257 
258  while (n_left_from > 0 && n_left_to_next > 0)
259  {
260  vlib_buffer_t *p0;
261  ethernet_header_t *eth0;
262  ethernet_arp_header_t *arp0;
263  ip6_header_t *iph0;
264  u8 *l3h0;
265  u32 pi0, error0, next0, sw_if_index0;
266  u16 ethertype0;
267  u16 bd_index0;
268  u32 ip0;
269  u8 *macp0;
270 
271  pi0 = from[0];
272  to_next[0] = pi0;
273  from += 1;
274  to_next += 1;
275  n_left_from -= 1;
276  n_left_to_next -= 1;
277 
278  p0 = vlib_get_buffer (vm, pi0);
279  // Terminate only local (SHG == 0) ARP
280  if (vnet_buffer (p0)->l2.shg != 0)
281  goto next_l2_feature;
282 
283  eth0 = vlib_buffer_get_current (p0);
284  l3h0 = (u8 *) eth0 + vnet_buffer (p0)->l2.l2_len;
285  ethertype0 = clib_net_to_host_u16 (*(u16 *) (l3h0 - 2));
286  arp0 = (ethernet_arp_header_t *) l3h0;
287 
288  if (ethertype0 != ETHERNET_TYPE_ARP)
289  goto check_ip6_nd;
290 
291  if ((arp0->opcode !=
292  clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request)) &&
293  (arp0->opcode !=
294  clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply)))
295  goto check_ip6_nd;
296 
297  /* Must be ARP request/reply packet here */
298  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
299  (p0->flags & VLIB_BUFFER_IS_TRACED)))
300  {
301  u8 *t0 = vlib_add_trace (vm, node, p0,
302  sizeof (ethernet_arp_input_trace_t));
303  clib_memcpy_fast (t0, l3h0,
304  sizeof (ethernet_arp_input_trace_t));
305  }
306 
307  error0 = 0;
308  error0 =
309  (arp0->l2_type !=
310  clib_net_to_host_u16 (ETHERNET_ARP_HARDWARE_TYPE_ethernet)
311  ? ETHERNET_ARP_ERROR_l2_type_not_ethernet : error0);
312  error0 =
313  (arp0->l3_type !=
314  clib_net_to_host_u16 (ETHERNET_TYPE_IP4) ?
315  ETHERNET_ARP_ERROR_l3_type_not_ip4 : error0);
316 
317  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
318 
319  if (error0)
320  goto drop;
321 
322  /* Trash ARP packets whose ARP-level source addresses do not
323  match, or if requester address is mcast */
324  if (PREDICT_FALSE
326  arp0->ip4_over_ethernet[0].
327  mac.bytes))
328  || ethernet_address_cast (arp0->ip4_over_ethernet[0].mac.bytes))
329  {
330  /* VRRP virtual MAC may be different to SMAC in ARP reply */
332  (arp0->ip4_over_ethernet[0].mac.bytes, vrrp_prefix))
333  {
334  error0 = ETHERNET_ARP_ERROR_l2_address_mismatch;
335  goto drop;
336  }
337  }
338  if (PREDICT_FALSE
340  {
341  error0 = ETHERNET_ARP_ERROR_l3_src_address_not_local;
342  goto drop;
343  }
344 
345  /* Check if anyone want ARP request events for L2 BDs */
346  l2_arp_term_publish_v4_dp (sw_if_index0,
347  &arp0->ip4_over_ethernet[0]);
348 
349  /* lookup BD mac_by_ip4 hash table for MAC entry */
350  ip0 = arp0->ip4_over_ethernet[1].ip4.as_u32;
351  bd_index0 = vnet_buffer (p0)->l2.bd_index;
352  if (PREDICT_FALSE ((bd_index0 != last_bd_index)
353  || (last_bd_index == (u16) ~ 0)))
354  {
355  last_bd_index = bd_index0;
356  last_bd_config = vec_elt_at_index (l2im->bd_configs, bd_index0);
357  }
358  macp0 = (u8 *) hash_get (last_bd_config->mac_by_ip4, ip0);
359 
360  if (PREDICT_FALSE (!macp0))
361  goto next_l2_feature; /* MAC not found */
362  if (PREDICT_FALSE (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
363  arp0->ip4_over_ethernet[1].ip4.as_u32))
364  goto next_l2_feature; /* GARP */
365 
366  /* MAC found, send ARP reply -
367  Convert ARP request packet to ARP reply */
368  arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
369  arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
370  arp0->ip4_over_ethernet[0].ip4.as_u32 = ip0;
371  mac_address_from_bytes (&arp0->ip4_over_ethernet[0].mac, macp0);
372  clib_memcpy_fast (eth0->dst_address, eth0->src_address, 6);
373  clib_memcpy_fast (eth0->src_address, macp0, 6);
374  n_replies_sent += 1;
375 
376  output_response:
377  /* For BVI, need to use l2-fwd node to send ARP reply as
378  l2-output node cannot output packet to BVI properly */
379  cfg0 = vec_elt_at_index (l2im->configs, sw_if_index0);
380  if (PREDICT_FALSE (cfg0->bvi))
381  {
382  vnet_buffer (p0)->l2.feature_bitmap |= L2INPUT_FEAT_FWD;
383  vnet_buffer (p0)->sw_if_index[VLIB_RX] = 0;
384  goto next_l2_feature;
385  }
386 
387  /* Send ARP/ND reply back out input interface through l2-output */
388  vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
389  next0 = ARP_TERM_NEXT_L2_OUTPUT;
390  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
391  to_next, n_left_to_next, pi0,
392  next0);
393  continue;
394 
395  check_ip6_nd:
396  /* IP6 ND event notification or solicitation handling to generate
397  local response instead of flooding */
398  iph0 = (ip6_header_t *) l3h0;
399  if (PREDICT_FALSE (ethertype0 == ETHERNET_TYPE_IP6 &&
400  iph0->protocol == IP_PROTOCOL_ICMP6 &&
402  (&iph0->src_address)))
403  {
404  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
405  if (vnet_ip6_nd_term
406  (vm, node, p0, eth0, iph0, sw_if_index0,
407  vnet_buffer (p0)->l2.bd_index))
408  goto output_response;
409  }
410 
411  next_l2_feature:
412  {
414  L2INPUT_FEAT_ARP_TERM);
415  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
416  to_next, n_left_to_next,
417  pi0, next0);
418  continue;
419  }
420 
421  drop:
422  if (0 == arp0->ip4_over_ethernet[0].ip4.as_u32 ||
423  (arp0->ip4_over_ethernet[0].ip4.as_u32 ==
424  arp0->ip4_over_ethernet[1].ip4.as_u32))
425  {
426  error0 = ETHERNET_ARP_ERROR_gratuitous_arp;
427  }
428  next0 = ARP_TERM_NEXT_DROP;
429  p0->error = node->errors[error0];
430 
431  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
432  to_next, n_left_to_next, pi0,
433  next0);
434  }
435 
436  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
437  }
438 
439  vlib_error_count (vm, node->node_index,
440  ETHERNET_ARP_ERROR_replies_sent, n_replies_sent);
441  return frame->n_vectors;
442 }
443 
444 /* *INDENT-OFF* */
446  .function = arp_term_l2bd,
447  .name = "arp-term-l2bd",
448  .vector_size = sizeof (u32),
449  .n_errors = ETHERNET_ARP_N_ERROR,
450  .error_strings = ethernet_arp_error_strings,
451  .n_next_nodes = ARP_TERM_N_NEXT,
452  .next_nodes = {
453  [ARP_TERM_NEXT_L2_OUTPUT] = "l2-output",
454  [ARP_TERM_NEXT_DROP] = "error-drop",
455  },
456  .format_buffer = format_ethernet_arp_header,
457  .format_trace = format_arp_term_input_trace,
458 };
459 /* *INDENT-ON* */
460 
461 clib_error_t *
463 {
464  // Initialize the feature next-node indexes
466  arp_term_l2bd_node.index,
470  return 0;
471 }
472 
474 
475 /*
476  * fd.io coding-style-patch-verification: ON
477  *
478  * Local Variables:
479  * eval: (c-set-style "gnu")
480  * End:
481  */
#define ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED
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
l2_input_config_t * configs
Definition: l2_input.h:62
#define CLIB_UNUSED(x)
Definition: clib.h:82
vl_api_mac_address_t mac
Definition: l2.api:491
vlib_node_registration_t l2_arp_term_process_node
(constructor) VLIB_REGISTER_NODE (l2_arp_term_process_node)
Definition: l2_api.c:1133
a
Definition: bitmap.h:538
l2_arp_term_publish_event_t * publish_events
Definition: l2_arp_term.h:38
static void vlib_error_count(vlib_main_t *vm, uword node_index, uword counter, uword increment)
Definition: error_funcs.h:57
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
clib_error_t * arp_term_init(vlib_main_t *vm)
Definition: l2_arp_term.c:462
u8 src_address[6]
Definition: packet.h:56
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:523
void l2_arp_term_set_publisher_node(bool on)
Definition: l2_arp_term.c:99
arp_term_next_t
Definition: l2_arp_term.c:35
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
#define foreach_ethernet_arp_error
Definition: l2_arp_term.c:49
static uword ip4_address_is_multicast(const ip4_address_t *a)
Definition: ip4_packet.h:382
static void l2_arp_term_publish_v6_dp(u32 sw_if_index, const ip6_address_t *addr, const mac_address_t *mac)
Definition: l2_arp_term.c:141
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:470
vhost_vring_addr_t addr
Definition: vhost_user.h:147
ip6_address_t src_address
Definition: ip6_packet.h:307
unsigned char u8
Definition: types.h:56
static u32 vnet_l2_feature_next(vlib_buffer_t *b, u32 *next_nodes, u32 feat_bit)
Return the graph node index for the feature corresponding to the next set bit after clearing the curr...
Definition: feat_bitmap.h:94
#define clib_memcpy(d, s, n)
Definition: string.h:180
vl_api_interface_index_t sw_if_index
Definition: gre.api:59
ethernet_arp_ip4_over_ethernet_address_t ip4_over_ethernet[2]
Definition: arp_packet.h:142
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
static uword ethernet_address_cast(u8 *a)
Definition: packet.h:67
#define ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE
u8 dst_address[6]
Definition: packet.h:55
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
void vl_api_rpc_call_main_thread(void *fp, u8 *data, u32 data_length)
Definition: vlib_api.c:607
unsigned int u32
Definition: types.h:88
static int vnet_ip6_nd_term(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *p0, ethernet_header_t *eth, ip6_header_t *ip, u32 sw_if_index, u16 bd_index)
Definition: l2_arp_term.c:162
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
#define hash_get(h, key)
Definition: hash.h:249
static_always_inline void mac_address_from_bytes(mac_address_t *mac, const u8 *bytes)
Definition: mac_address.h:92
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:934
long ctx[MAX_CONNS]
Definition: main.c:144
unsigned short u16
Definition: types.h:57
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
#define PREDICT_FALSE(x)
Definition: clib.h:111
u32 node_index
Node index.
Definition: node.h:496
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
#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:338
vlib_main_t * vm
Definition: in2out_ed.c:1810
ethernet_arp_reply_error_t
Definition: l2_arp_term.c:67
vlib_node_registration_t ip6_icmp_input_node
(constructor) VLIB_REGISTER_NODE (ip6_icmp_input_node)
Definition: icmp6.c:240
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
u16 n_vectors
Definition: node.h:397
static void feat_bitmap_init_next_nodes(vlib_main_t *vm, u32 node_index, u32 num_features, char **feat_names, u32 *next_nodes)
Initialize the feature next-node indexes of a graph node.
Definition: feat_bitmap.h:43
static int ethernet_mac_address_equal(const u8 *a, const u8 *b)
Definition: mac_address.h:85
static vlib_node_runtime_t * vlib_node_get_runtime(vlib_main_t *vm, u32 node_index)
Get node runtime by node index.
Definition: node_funcs.h:89
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:456
uword * mac_by_ip6
Definition: l2_bd.h:102
static vlib_node_registration_t arp_term_l2bd_node
(constructor) VLIB_REGISTER_NODE (arp_term_l2bd_node)
Definition: l2_arp_term.c:445
char ** l2input_get_feat_names(void)
Return an array of strings containing graph node names of each feature.
Definition: l2_input.c:62
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1810
static void * ip6_next_header(ip6_header_t *i)
Definition: ip6_packet.h:368
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:1021
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:515
static const u8 vrrp_prefix[]
Definition: l2_arp_term.c:27
static uword ip6_address_is_link_local_unicast(const ip6_address_t *a)
Definition: ip6_packet.h:250
format_function_t format_ip6_header
Definition: format.h:95
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
Definition: defs.h:47
l2input_main_t l2input_main
Definition: l2_input.c:128
vl_api_address_t ip
Definition: l2.api:490
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:244
static uword arp_term_l2bd(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: l2_arp_term.c:238
u32 arp_term_next_node_index[32]
Definition: l2_arp_term.c:42
l2_bridge_domain_t * bd_configs
Definition: l2_input.h:65
#define hash_get_mem(h, key)
Definition: hash.h:269
u8 * format_ethernet_arp_header(u8 *s, va_list *va)
Definition: arp_packet.c:59
static uword ip6_address_is_unspecified(const ip6_address_t *a)
Definition: ip6_packet.h:234
#define vnet_buffer(b)
Definition: buffer.h:408
static char * ethernet_arp_error_strings[]
Definition: l2_arp_term.c:75
static u8 * format_arp_term_input_trace(u8 *s, va_list *va)
Definition: l2_arp_term.c:82
uword * mac_by_ip4
Definition: l2_bd.h:101
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1811
u16 flags
Copy of main node flags.
Definition: node.h:509
static void l2_arp_term_publish_v4_dp(u32 sw_if_index, const ethernet_arp_ip4_over_ethernet_address_t *a)
Definition: l2_arp_term.c:121
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:302
l2_arp_term_main_t l2_arp_term_main
Definition: l2_arp_term.c:29
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
Definition: defs.h:46
static int l2_arp_term_publish(l2_arp_term_publish_event_t *ctx)
Definition: l2_arp_term.c:107
ip6_address_t dst_address
Definition: ip6_packet.h:307