FD.io VPP  v20.01-48-g3e0dafb74
Vector Packet Processing
arp_proxy.c
Go to the documentation of this file.
1 /*
2  * ethernet/arp.c: IP v4 ARP node
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 <vnet/arp/arp.h>
19 #include <vnet/arp/arp_packet.h>
20 
21 #include <vnet/fib/ip4_fib.h>
22 
23 typedef struct
24 {
29 
30 typedef struct arp_proxy_main_t_
31 {
32  /** Per interface state */
34 
35  /* Proxy arp vector */
38 
40 
41 void
43 {
46 
47  vec_foreach (pa, am->proxy_arps)
48  {
49  if (!cb (&pa->lo_addr, &pa->hi_addr, pa->fib_index, data))
50  break;
51  }
52 }
53 
54 int
56 {
58 
59  vec_validate (am->enabled_by_sw_if_index, sw_if_index);
60 
61  if (am->enabled_by_sw_if_index[sw_if_index])
62  {
63  vnet_feature_enable_disable ("arp", "arp-proxy",
64  sw_if_index, 0, NULL, 0);
65  }
67 
68  return (0);
69 }
70 
71 int
73 {
75 
76  vec_validate (am->enabled_by_sw_if_index, sw_if_index);
77 
78  if (!am->enabled_by_sw_if_index[sw_if_index])
79  {
80  vnet_feature_enable_disable ("arp", "arp-proxy",
81  sw_if_index, 1, NULL, 0);
82  }
84 
85  return (0);
86 }
87 
88 static int
90  const ip4_address_t * hi_addr,
91  u32 fib_index, int is_del)
92 {
95  u32 found_at_index = ~0;
96 
97  vec_foreach (pa, am->proxy_arps)
98  {
99  if (pa->lo_addr.as_u32 == lo_addr->as_u32 &&
100  pa->hi_addr.as_u32 == hi_addr->as_u32 && pa->fib_index == fib_index)
101  {
102  found_at_index = pa - am->proxy_arps;
103  break;
104  }
105  }
106 
107  if (found_at_index != ~0)
108  {
109  /* Delete, otherwise it's already in the table */
110  if (is_del)
111  vec_delete (am->proxy_arps, 1, found_at_index);
112  return 0;
113  }
114  /* delete, no such entry */
115  if (is_del)
116  return VNET_API_ERROR_NO_SUCH_ENTRY;
117 
118  /* add, not in table */
119  vec_add2 (am->proxy_arps, pa, 1);
120  pa->lo_addr.as_u32 = lo_addr->as_u32;
121  pa->hi_addr.as_u32 = hi_addr->as_u32;
122  pa->fib_index = fib_index;
123  return 0;
124 }
125 
126 int
127 arp_proxy_add (u32 fib_index,
128  const ip4_address_t * lo, const ip4_address_t * hi)
129 {
130  return (vnet_proxy_arp_add_del (lo, hi, fib_index, 0));
131 }
132 
133 int
134 arp_proxy_del (u32 fib_index,
135  const ip4_address_t * lo, const ip4_address_t * hi)
136 {
137  return (vnet_proxy_arp_add_del (lo, hi, fib_index, 1));
138 }
139 
140 void
142 {
144  bool *enabled;
145 
146  vec_foreach (enabled, am->enabled_by_sw_if_index)
147  {
148  if (*enabled)
149  cb (enabled - am->enabled_by_sw_if_index, data);
150  }
151 }
152 
153 static clib_error_t *
156  input, vlib_cli_command_t * cmd)
157 {
158  vnet_main_t *vnm = vnet_get_main ();
160  int enable = 0;
161 
162  sw_if_index = ~0;
163 
165  {
166  if (unformat (input, "%U", unformat_vnet_sw_interface,
167  vnm, &sw_if_index))
168  ;
169  else if (unformat (input, "enable") || unformat (input, "on"))
170  enable = 1;
171  else if (unformat (input, "disable") || unformat (input, "off"))
172  enable = 0;
173  else
174  break;
175  }
176 
177  if (~0 == sw_if_index)
178  return clib_error_return (0, "unknown input '%U'",
179  format_unformat_error, input);
180 
181  if (enable)
182  arp_proxy_enable (sw_if_index);
183  else
184  arp_proxy_disable (sw_if_index);
185 
186  return 0;
187 }
188 
189 /* *INDENT-OFF* */
190 /*?
191  * Enable proxy-arp on an interface. The vpp stack will answer ARP
192  * requests for the indicated address range. Multiple proxy-arp
193  * ranges may be provisioned.
194  *
195  * @note Proxy ARP as a technology is infamous for blackholing traffic.
196  * Also, the underlying implementation has not been performance-tuned.
197  * Avoid creating an unnecessarily large set of ranges.
198  *
199  * @cliexpar
200  * To enable proxy arp on a range of addresses, use:
201  * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11}
202  * Append 'del' to delete a range of proxy ARP addresses:
203  * @cliexcmd{set ip arp proxy 6.0.0.1 - 6.0.0.11 del}
204  * You must then specifically enable proxy arp on individual interfaces:
205  * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 enable}
206  * To disable proxy arp on an individual interface:
207  * @cliexcmd{set interface proxy-arp GigabitEthernet0/8/0 disable}
208  ?*/
209 VLIB_CLI_COMMAND (set_int_proxy_enable_command, static) = {
210  .path = "set interface proxy-arp",
211  .short_help =
212  "set interface proxy-arp <intfc> [enable|disable]",
213  .function = set_int_proxy_arp_command_fn,
214 };
215 /* *INDENT-ON* */
216 
217 typedef struct
218 {
219  u8 packet_data[64];
221 
222 static u8 *
224 {
225  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
226  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
228 
229  s = format (s, "%U",
231  t->packet_data, sizeof (t->packet_data));
232 
233  return s;
234 }
235 
236 static uword
238 {
240  vnet_main_t *vnm = vnet_get_main ();
241  u32 n_left_from, next_index, *from, *to_next;
242  u32 n_arp_replies_sent = 0;
243 
244  from = vlib_frame_vector_args (frame);
245  n_left_from = frame->n_vectors;
246  next_index = node->cached_next_index;
247 
248  if (node->flags & VLIB_NODE_FLAG_TRACE)
249  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
250  /* stride */ 1,
251  sizeof (ethernet_arp_input_trace_t));
252 
253  while (n_left_from > 0)
254  {
255  u32 n_left_to_next;
256 
257  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
258 
259  while (n_left_from > 0 && n_left_to_next > 0)
260  {
261  vlib_buffer_t *p0;
262  ethernet_arp_header_t *arp0;
263  ethernet_header_t *eth_rx;
264  ip4_address_t proxy_src;
265  u32 pi0, error0, next0, sw_if_index0, fib_index0;
266  u8 is_request0;
268 
269  pi0 = from[0];
270  to_next[0] = pi0;
271  from += 1;
272  to_next += 1;
273  n_left_from -= 1;
274  n_left_to_next -= 1;
275 
276  p0 = vlib_get_buffer (vm, pi0);
277  arp0 = vlib_buffer_get_current (p0);
278  /* Fill in ethernet header. */
279  eth_rx = ethernet_buffer_get_header (p0);
280 
281  is_request0 = arp0->opcode
282  == clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request);
283 
284  error0 = ETHERNET_ARP_ERROR_replies_sent;
285  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
286  next0 = ARP_REPLY_NEXT_DROP;
287 
288  fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
289  if (~0 == fib_index0)
290  {
291  error0 = ETHERNET_ARP_ERROR_interface_no_table;
292  }
293 
294  if (0 == error0 && is_request0)
295  {
296  u32 this_addr = clib_net_to_host_u32
297  (arp0->ip4_over_ethernet[1].ip4.as_u32);
298 
299  vec_foreach (pa, am->proxy_arps)
300  {
301  u32 lo_addr = clib_net_to_host_u32 (pa->lo_addr.as_u32);
302  u32 hi_addr = clib_net_to_host_u32 (pa->hi_addr.as_u32);
303 
304  /* an ARP request hit in the proxy-arp table? */
305  if ((this_addr >= lo_addr && this_addr <= hi_addr) &&
306  (fib_index0 == pa->fib_index))
307  {
308  proxy_src.as_u32 =
309  arp0->ip4_over_ethernet[1].ip4.data_u32;
310 
311  /*
312  * change the interface address to the proxied
313  */
314  n_arp_replies_sent++;
315 
316  next0 =
317  arp_mk_reply (vnm, p0, sw_if_index0, &proxy_src, arp0,
318  eth_rx);
319  }
320  }
321  }
322  else
323  {
324  p0->error = node->errors[error0];
325  }
326 
327  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
328  n_left_to_next, pi0, next0);
329  }
330 
331  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
332  }
333 
334  vlib_error_count (vm, node->node_index,
335  ETHERNET_ARP_ERROR_replies_sent, n_arp_replies_sent);
336 
337  return frame->n_vectors;
338 }
339 
340 static char *ethernet_arp_error_strings[] = {
341 #define _(sym,string) string,
343 #undef _
344 };
345 
347 {
348  .function = arp_proxy,.name = "arp-proxy",.vector_size =
349  sizeof (u32),.n_errors = ETHERNET_ARP_N_ERROR,.error_strings =
350  ethernet_arp_error_strings,.n_next_nodes = ARP_REPLY_N_NEXT,.next_nodes =
351  {
352  [ARP_REPLY_NEXT_DROP] = "error-drop",
353  [ARP_REPLY_NEXT_REPLY_TX] = "interface-output",}
354 ,.format_buffer = format_ethernet_arp_header,.format_trace =
356 
357 static clib_error_t *
359  unformat_input_t * input, vlib_cli_command_t * cmd)
360 {
363 
364  if (vec_len (am->proxy_arps))
365  {
366  vlib_cli_output (vm, "Proxy arps enabled for:");
367  vec_foreach (pa, am->proxy_arps)
368  {
369  vlib_cli_output (vm, "Fib_index %d %U - %U ",
370  pa->fib_index,
373  }
374  }
375 
376  return (NULL);
377 }
378 
379 /*?
380  * Display all the IPv4 ARP proxy entries.
381  *
382  * @cliexpar
383  * Example of how to display the IPv4 ARP table:
384  * @cliexstart{show ip arp}
385  * Time FIB IP4 Flags Ethernet Interface
386  * 346.3028 0 6.1.1.3 de:ad:be:ef:ba:be GigabitEthernet2/0/0
387  * 3077.4271 0 6.1.1.4 S de:ad:be:ef:ff:ff GigabitEthernet2/0/0
388  * 2998.6409 1 6.2.2.3 de:ad:be:ef:00:01 GigabitEthernet2/0/0
389  * Proxy arps enabled for:
390  * Fib_index 0 6.0.0.1 - 6.0.0.11
391  * @cliexend
392  ?*/
393 /* *INDENT-OFF* */
394 VLIB_CLI_COMMAND (show_ip4_arp_command, static) = {
395  .path = "show arp proxy",
396  .function = show_ip4_arp,
397  .short_help = "show ip arp",
398 };
399 /* *INDENT-ON* */
400 
401 /*
402  * fd.io coding-style-patch-verification: ON
403  *
404  * Local Variables:
405  * eval: (c-set-style "gnu")
406  * End:
407  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:440
#define foreach_ethernet_arp_error
Definition: arp.h:23
arp_proxy_main_t arp_proxy_main
Definition: arp_proxy.c:39
#define CLIB_UNUSED(x)
Definition: clib.h:82
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
int arp_proxy_add(u32 fib_index, const ip4_address_t *lo, const ip4_address_t *hi)
Definition: arp_proxy.c:127
static void vlib_error_count(vlib_main_t *vm, uword node_index, uword counter, uword increment)
Definition: error_funcs.h:57
#define NULL
Definition: clib.h:58
bool * enabled_by_sw_if_index
Per interface state.
Definition: arp_proxy.c:33
static u8 * format_ethernet_arp_input_trace(u8 *s, va_list *va)
Definition: arp_proxy.c:223
static clib_error_t * show_ip4_arp(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: arp_proxy.c:358
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:561
ethernet_proxy_arp_t * proxy_arps
Definition: arp_proxy.c:36
void proxy_arp_intfc_walk(proxy_arp_intf_walk_t cb, void *data)
Definition: arp_proxy.c:141
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
unformat_function_t unformat_vnet_sw_interface
static vlib_node_registration_t arp_proxy_node
(constructor) VLIB_REGISTER_NODE (arp_proxy_node)
Definition: arp_proxy.c:346
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:470
static char * ethernet_arp_error_strings[]
Definition: arp_proxy.c:340
unsigned char u8
Definition: types.h:56
u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip4_fib.c:230
format_function_t format_ip4_address
Definition: format.h:73
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 clib_error_return(e, args...)
Definition: error.h:99
unsigned int u32
Definition: types.h:88
void proxy_arp_walk(proxy_arp_walk_t cb, void *data)
Definition: arp_proxy.c:42
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
static ethernet_header_t * ethernet_buffer_get_header(vlib_buffer_t *b)
Definition: ethernet.h:398
lo
static clib_error_t * set_int_proxy_arp_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: arp_proxy.c:154
struct _unformat_input_t unformat_input_t
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
int arp_proxy_enable(u32 sw_if_index)
Definition: arp_proxy.c:72
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
static_always_inline u32 arp_mk_reply(vnet_main_t *vnm, vlib_buffer_t *p0, u32 sw_if_index0, const ip4_address_t *if_addr0, ethernet_arp_header_t *arp0, ethernet_header_t *eth_rx)
Definition: arp_packet.h:32
#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
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
int arp_proxy_disable(u32 sw_if_index)
Definition: arp_proxy.c:55
u16 n_vectors
Definition: node.h:397
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
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1810
walk_rc_t() proxy_arp_intf_walk_t(u32 sw_if_index, void *data)
call back function when walking the DB of proxy ARP interface
Definition: arp.h:73
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:152
int arp_proxy_del(u32 fib_index, const ip4_address_t *lo, const ip4_address_t *hi)
Definition: arp_proxy.c:134
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:515
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:785
u8 data[128]
Definition: ipsec_types.api:87
walk_rc_t() proxy_arp_walk_t(const ip4_address_t *lo_addr, const ip4_address_t *hi_addr, u32 fib_index, void *dat)
call back function when walking the DB of proxy ARPs
Definition: arp.h:63
static int vnet_proxy_arp_add_del(const ip4_address_t *lo_addr, const ip4_address_t *hi_addr, u32 fib_index, int is_del)
Definition: arp_proxy.c:89
vl_api_ip4_address_t hi
Definition: arp.api:37
void vlib_trace_frame_buffers_only(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, uword n_buffers, uword next_buffer_stride, uword n_buffer_data_bytes_in_trace)
Definition: trace.c:47
ip4_address_t hi_addr
Definition: arp_proxy.c:26
struct arp_proxy_main_t_ arp_proxy_main_t
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
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_proxy(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: arp_proxy.c:237
u8 * format_ethernet_arp_header(u8 *s, va_list *va)
Definition: arp_packet.c:59
ip4_address_t lo_addr
Definition: arp_proxy.c:25
#define vnet_buffer(b)
Definition: buffer.h:408
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
#define vec_foreach(var, vec)
Vector iterator.
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
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:302
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:689
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
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
Definition: defs.h:46
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: feature.c:304
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171