FD.io VPP  v17.10-9-gd594711
Vector Packet Processing
sixrd.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "sixrd.h"
17 #include <vnet/plugin/plugin.h>
18 
19 #include <vnet/fib/fib_table.h>
20 #include <vnet/fib/ip6_fib.h>
21 #include <vnet/adj/adj.h>
22 #include <vpp/app/version.h>
23 
24 /*
25  * This code supports the following sixrd modes:
26  *
27  * 32 EA bits (Complete IPv4 address is embedded):
28  * ea_bits_len = 32
29  * IPv4 suffix is embedded:
30  * ea_bits_len = < 32
31  * No embedded address bits (1:1 mode):
32  * ea_bits_len = 0
33  */
34 
35 int
37  u8 ip6_prefix_len,
38  ip4_address_t *ip4_prefix,
39  u8 ip4_prefix_len,
40  ip4_address_t *ip4_src,
41  u32 *sixrd_domain_index,
42  u16 mtu)
43 {
44  dpo_id_t dpo_v6 = DPO_INVALID, dpo_v4 = DPO_INVALID;
45  sixrd_main_t *mm = &sixrd_main;
46  fib_node_index_t fei;
47  sixrd_domain_t *d;
48 
49  /* Get domain index */
51  memset(d, 0, sizeof (*d));
52  *sixrd_domain_index = d - mm->domains;
53 
54  /* Init domain struct */
55  d->ip4_prefix.as_u32 = ip4_prefix->as_u32;
56  d->ip4_prefix_len = ip4_prefix_len;
57  d->ip6_prefix = *ip6_prefix;
58  d->ip6_prefix_len = ip6_prefix_len;
59  d->ip4_src = *ip4_src;
60  d->mtu = mtu;
61 
62  if (ip4_prefix_len < 32)
63  d->shift = 64 - ip6_prefix_len + (32 - ip4_prefix_len);
64 
65  /* Create IPv6 route/adjacency */
66  fib_prefix_t pfx6 = {
68  .fp_len = d->ip6_prefix_len,
69  .fp_addr = {
70  .ip6 = d->ip6_prefix,
71  },
72  };
74  *sixrd_domain_index,
75  &dpo_v6);
79  &dpo_v6);
80  dpo_reset (&dpo_v6);
81 
82  /*
83  * Multiple SIXRD domains may share same source IPv4 TEP
84  * In this case the route will exist and be SixRD sourced.
85  * Find the adj (if any) already contributed and modify it
86  */
87  fib_prefix_t pfx4 = {
89  .fp_len = 32,
90  .fp_addr = {
91  .ip4 = d->ip4_src,
92  },
93  };
94  fei = fib_table_lookup_exact_match(0, &pfx4);
95 
96  if (FIB_NODE_INDEX_INVALID != fei)
97  {
98  dpo_id_t dpo = DPO_INVALID;
99 
101  {
102  /*
103  * modify the existing adj to indicate it's shared
104  * skip to route add.
105  * It is locked to pair with the unlock below.
106  */
107  const dpo_id_t *sd_dpo;
108  sixrd_dpo_t *sd;
109 
111 
112  sd_dpo = load_balance_get_bucket(dpo.dpoi_index, 0);
113  sd = sixrd_dpo_get (sd_dpo->dpoi_index);
114 
115  sd->sd_domain = ~0;
116  dpo_copy (&dpo_v4, sd_dpo);
117  dpo_reset (&dpo);
118 
119  goto route_add;
120  }
121  }
122  /* first time addition of the route */
124  *sixrd_domain_index,
125  &dpo_v4);
126 
127 route_add:
128  /*
129  * Create ip4 route. This is a reference counted add. If the prefix
130  * already exists and is SixRD sourced, it is now SixRD source n+1 times
131  * and will need to be removed n+1 times.
132  */
136  &dpo_v4);
137  dpo_reset (&dpo_v4);
138 
139  return 0;
140 }
141 
142 /*
143  * sixrd_delete_domain
144  */
145 int
146 sixrd_delete_domain (u32 sixrd_domain_index)
147 {
148  sixrd_main_t *mm = &sixrd_main;
149  sixrd_domain_t *d;
150 
151  if (pool_is_free_index(mm->domains, sixrd_domain_index)) {
152  clib_warning("SIXRD domain delete: domain does not exist: %d",
153  sixrd_domain_index);
154  return -1;
155  }
156 
157  d = pool_elt_at_index(mm->domains, sixrd_domain_index);
158 
159  fib_prefix_t pfx = {
161  .fp_len = 32,
162  .fp_addr = {
163  .ip4 = d->ip4_src,
164  },
165  };
167 
168  fib_prefix_t pfx6 = {
170  .fp_len = d->ip6_prefix_len,
171  .fp_addr = {
172  .ip6 = d->ip6_prefix,
173  },
174  };
176 
177  pool_put(mm->domains, d);
178 
179  return 0;
180 }
181 
182 static clib_error_t *
184  unformat_input_t *input,
185  vlib_cli_command_t *cmd)
186 {
187  unformat_input_t _line_input, *line_input = &_line_input;
188  ip4_address_t ip4_prefix;
189  ip6_address_t ip6_prefix;
190  ip4_address_t ip4_src;
191  u32 ip6_prefix_len=0, ip4_prefix_len=0, sixrd_domain_index;
192  u32 num_m_args = 0;
193  /* Optional arguments */
194  u32 mtu = 0;
195  clib_error_t *error = 0;
196 
197  /* Get a line of input. */
198  if (!unformat_user(input, unformat_line_input, line_input))
199  return 0;
200  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
201  if (unformat(line_input, "ip6-pfx %U/%d", unformat_ip6_address, &ip6_prefix, &ip6_prefix_len))
202  num_m_args++;
203  else if (unformat(line_input, "ip4-pfx %U/%d", unformat_ip4_address, &ip4_prefix, &ip4_prefix_len))
204  num_m_args++;
205  else if (unformat(line_input, "ip4-src %U", unformat_ip4_address, &ip4_src))
206  num_m_args++;
207  else if (unformat(line_input, "mtu %d", &mtu))
208  num_m_args++;
209  else {
210  error = clib_error_return(0, "unknown input `%U'",
211  format_unformat_error, line_input);
212  goto done;
213  }
214  }
215 
216  if (num_m_args < 3) {
217  error = clib_error_return(0, "mandatory argument(s) missing");
218  goto done;
219  }
220 
221  sixrd_create_domain(&ip6_prefix, ip6_prefix_len, &ip4_prefix, ip4_prefix_len,
222  &ip4_src, &sixrd_domain_index, mtu);
223 
224 done:
225  unformat_free (line_input);
226 
227  return error;
228 }
229 
230 static clib_error_t *
232  unformat_input_t *input,
233  vlib_cli_command_t *cmd)
234 {
235  unformat_input_t _line_input, *line_input = &_line_input;
236  u32 num_m_args = 0;
237  u32 sixrd_domain_index;
238  clib_error_t *error = 0;
239 
240  /* Get a line of input. */
241  if (! unformat_user(input, unformat_line_input, line_input))
242  return 0;
243 
244  while (unformat_check_input(line_input) != UNFORMAT_END_OF_INPUT) {
245  if (unformat(line_input, "index %d", &sixrd_domain_index))
246  num_m_args++;
247  else {
248  error = clib_error_return(0, "unknown input `%U'",
249  format_unformat_error, line_input);
250  goto done;
251  }
252  }
253 
254  if (num_m_args != 1) {
255  error = clib_error_return(0, "mandatory argument(s) missing");
256  goto done;
257  }
258 
259  sixrd_delete_domain(sixrd_domain_index);
260 
261 done:
262  unformat_free (line_input);
263 
264  return error;
265 }
266 
267 static u8 *
268 format_sixrd_domain (u8 *s, va_list *args)
269 {
270  sixrd_domain_t *d = va_arg(*args, sixrd_domain_t *);
271  sixrd_main_t *mm = &sixrd_main;
272 
273  s = format(s,
274  "[%d] ip6-pfx %U/%d ip4-pfx %U/%d ip4-src %U mtu %d",
275  d - mm->domains,
278  format_ip4_address, &d->ip4_src, d->mtu);
279 
280  return s;
281 }
282 
283 static clib_error_t *
285 {
286  sixrd_main_t *mm = &sixrd_main;
287  sixrd_domain_t *d;
288 
289  if (pool_elts(mm->domains) == 0)
290  vlib_cli_output(vm, "No SIXRD domains are configured...");
291 
292  pool_foreach(d, mm->domains, ({vlib_cli_output(vm, "%U", format_sixrd_domain, d);}));
293 
294  return 0;
295 
296 }
297 
298 static clib_error_t *
300 {
301  sixrd_main_t *mm = &sixrd_main;
302  sixrd_domain_t *d;
303  int domains = 0, domaincount = 0;
304  if (pool_elts (mm->domains) == 0)
305  vlib_cli_output (vm, "No SIXRD domains are configured...");
306 
307  pool_foreach(d, mm->domains, ({
308  domains += sizeof(*d);
309  domaincount++;
310  }));
311 
312  vlib_cli_output(vm, "SIXRD domains structure: %d\n", sizeof (sixrd_domain_t));
313  vlib_cli_output(vm, "SIXRD domains: %d (%d bytes)\n", domaincount, domains);
314 
315  return 0;
316 }
317 
318 /*
319  * packet trace format function
320  */
321 u8 *
322 format_sixrd_trace (u8 *s, va_list *args)
323 {
324  CLIB_UNUSED(vlib_main_t *vm) = va_arg (*args, vlib_main_t *);
325  CLIB_UNUSED(vlib_node_t *node) = va_arg (*args, vlib_node_t *);
326  sixrd_trace_t *t = va_arg (*args, sixrd_trace_t *);
327  u32 sixrd_domain_index = t->sixrd_domain_index;
328 
329  s = format(s, "SIXRD domain index: %d", sixrd_domain_index);
330 
331  return s;
332 }
333 
334 VLIB_CLI_COMMAND(sixrd_add_domain_command, static) = {
335  .path = "sixrd add domain",
336  .short_help =
337  "sixrd add domain ip6-pfx <ip6-pfx> ip4-pfx <ip4-pfx> ip4-src <ip4-addr>",
338  .function = sixrd_add_domain_command_fn,
339 };
340 
341 VLIB_CLI_COMMAND(sixrd_del_command, static) = {
342  .path = "sixrd del domain",
343  .short_help =
344  "sixrd del domain index <domain>",
345  .function = sixrd_del_domain_command_fn,
346 };
347 
348 VLIB_CLI_COMMAND(show_sixrd_domain_command, static) = {
349  .path = "show sixrd domain",
350  .function = show_sixrd_domain_command_fn,
351 };
352 
353 VLIB_CLI_COMMAND(show_sixrd_stats_command, static) = {
354  .path = "show sixrd stats",
355  .function = show_sixrd_stats_command_fn,
356 };
357 
358 /* *INDENT-OFF* */
360  .version = VPP_BUILD_VER,
361  .description = "IPv6 Rapid Deployment on IPv4 Infrastructure (RFC5969)",
362 };
363 /* *INDENT-ON* */
364 
366 {
367  sixrd_main_t *mm = &sixrd_main;
368 
369  mm->vnet_main = vnet_get_main();
370  mm->vlib_main = vm;
371 
373 
374  return (NULL);
375 }
376 
ip4_address_t ip4_src
Definition: sixrd.h:33
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:169
vlib_main_t * vlib_main
Definition: sixrd.h:48
#define CLIB_UNUSED(x)
Definition: clib.h:79
fib_node_index_t fib_table_lookup_exact_match(u32 fib_index, const fib_prefix_t *prefix)
Perfom an exact match in the non-forwarding table.
Definition: fib_table.c:95
void sixrd_dpo_create(dpo_proto_t dproto, u32 domain_index, dpo_id_t *dpo)
Definition: sixrd_dpo.c:47
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static clib_error_t * show_sixrd_stats_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: sixrd.c:299
#define NULL
Definition: clib.h:55
static u8 * format_sixrd_domain(u8 *s, va_list *args)
Definition: sixrd.c:268
void dpo_copy(dpo_id_t *dst, const dpo_id_t *src)
atomic copy a data-plane object.
Definition: dpo.c:255
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:983
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
static clib_error_t * sixrd_add_domain_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: sixrd.c:183
SIXRD.
Definition: fib_entry.h:78
u8 ip4_prefix_len
Definition: sixrd.h:35
u32 sd_domain
the SIXRD domain index
Definition: sixrd_dpo.h:35
format_function_t format_ip4_address
Definition: format.h:79
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:437
unformat_function_t unformat_ip4_address
Definition: format.h:76
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
void fib_table_entry_special_remove(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source)
Remove a &#39;special&#39; entry from the FIB.
Definition: fib_table.c:390
vnet_main_t * vnet_main
Definition: sixrd.h:49
Aggregrate type for a prefix.
Definition: fib_types.h:160
#define clib_error_return(e, args...)
Definition: error.h:99
ip4_address_t ip4_prefix
Definition: sixrd.h:32
const int fib_entry_get_dpo_for_source(fib_node_index_t fib_entry_index, fib_source_t source, dpo_id_t *dpo)
unformat_function_t unformat_line_input
Definition: format.h:281
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:150
Definition: fib_entry.h:232
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:458
static clib_error_t * show_sixrd_domain_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: sixrd.c:284
dpo_type_t dpoi_type
the type
Definition: dpo.h:154
static clib_error_t * sixrd_del_domain_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: sixrd.c:231
struct _unformat_input_t unformat_input_t
load-balancing over a choice of [un]equal cost paths
Definition: dpo.h:100
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:270
static sixrd_dpo_t * sixrd_dpo_get(index_t index)
Definition: sixrd_dpo.h:54
sixrd_main_t sixrd_main
Definition: sixrd.h:82
const dpo_id_t * load_balance_get_bucket(index_t lbi, u32 bucket)
Definition: load_balance.c:283
unformat_function_t unformat_ip6_address
Definition: format.h:94
#define pool_get_aligned(P, E, A)
Allocate an object E from a pool P (general version).
Definition: pool.h:188
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
format_function_t format_ip6_address
Definition: format.h:95
vlib_main_t * vm
Definition: buffer.c:283
int sixrd_delete_domain(u32 sixrd_domain_index)
Definition: sixrd.c:146
#define clib_warning(format, args...)
Definition: error.h:59
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:28
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:267
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
fib_node_index_t fib_table_entry_special_dpo_add(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, const dpo_id_t *dpo)
Add a &#39;special&#39; entry to the FIB that links to the DPO passed A special entry is an entry that the FI...
Definition: fib_table.c:290
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
ip6_address_t ip6_prefix
Definition: sixrd.h:31
static clib_error_t * sixrd_init(vlib_main_t *vm)
Definition: sixrd.c:365
sixrd_domain_t * domains
Definition: sixrd.h:45
u32 sixrd_domain_index
Definition: sixrd.h:79
u8 * format_sixrd_trace(u8 *s, va_list *args)
Definition: sixrd.c:322
unsigned short u16
Definition: types.h:57
index_t dpoi_index
the index of objects of that type
Definition: dpo.h:166
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:29
unsigned char u8
Definition: types.h:56
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
int sixrd_create_domain(ip6_address_t *ip6_prefix, u8 ip6_prefix_len, ip4_address_t *ip4_prefix, u8 ip4_prefix_len, ip4_address_t *ip4_src, u32 *sixrd_domain_index, u16 mtu)
Definition: sixrd.c:36
#define DPO_INVALID
An initialiser for DPOs declared on the stack.
Definition: dpo.h:177
A representation of a 6RD DPO.
Definition: sixrd_dpo.h:25
VLIB_PLUGIN_REGISTER()
u8 ip6_prefix_len
Definition: sixrd.h:34
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
void dpo_reset(dpo_id_t *dpo)
reset a DPO ID The DPO will be unlocked.
Definition: dpo.c:225
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:680
void sixrd_dpo_module_init(void)
Definition: sixrd_dpo.c:129
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128