FD.io VPP  v18.01-8-g0eacf49
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 
36 
37 int
39  u8 ip6_prefix_len,
40  ip4_address_t *ip4_prefix,
41  u8 ip4_prefix_len,
42  ip4_address_t *ip4_src,
43  u32 *sixrd_domain_index,
44  u16 mtu)
45 {
46  dpo_id_t dpo_v6 = DPO_INVALID, dpo_v4 = DPO_INVALID;
47  sixrd_main_t *mm = &sixrd_main;
48  fib_node_index_t fei;
49  sixrd_domain_t *d;
50 
51  /* Get domain index */
53  memset(d, 0, sizeof (*d));
54  *sixrd_domain_index = d - mm->domains;
55 
56  /* Init domain struct */
57  d->ip4_prefix.as_u32 = ip4_prefix->as_u32;
58  d->ip4_prefix_len = ip4_prefix_len;
59  d->ip6_prefix = *ip6_prefix;
60  d->ip6_prefix_len = ip6_prefix_len;
61  d->ip4_src = *ip4_src;
62  d->mtu = mtu;
63 
64  if (ip4_prefix_len < 32)
65  d->shift = 64 - ip6_prefix_len + (32 - ip4_prefix_len);
66 
67  /* Create IPv6 route/adjacency */
68  fib_prefix_t pfx6 = {
70  .fp_len = d->ip6_prefix_len,
71  .fp_addr = {
72  .ip6 = d->ip6_prefix,
73  },
74  };
76  *sixrd_domain_index,
77  &dpo_v6);
81  &dpo_v6);
82  dpo_reset (&dpo_v6);
83 
84  /*
85  * Multiple SIXRD domains may share same source IPv4 TEP
86  * In this case the route will exist and be SixRD sourced.
87  * Find the adj (if any) already contributed and modify it
88  */
89  fib_prefix_t pfx4 = {
91  .fp_len = 32,
92  .fp_addr = {
93  .ip4 = d->ip4_src,
94  },
95  };
96  fei = fib_table_lookup_exact_match(0, &pfx4);
97 
98  if (FIB_NODE_INDEX_INVALID != fei)
99  {
100  dpo_id_t dpo = DPO_INVALID;
101 
103  {
104  /*
105  * modify the existing adj to indicate it's shared
106  * skip to route add.
107  * It is locked to pair with the unlock below.
108  */
109  const dpo_id_t *sd_dpo;
110  sixrd_dpo_t *sd;
111 
113 
114  sd_dpo = load_balance_get_bucket(dpo.dpoi_index, 0);
115  sd = sixrd_dpo_get (sd_dpo->dpoi_index);
116 
117  sd->sd_domain = ~0;
118  dpo_copy (&dpo_v4, sd_dpo);
119  dpo_reset (&dpo);
120 
121  goto route_add;
122  }
123  }
124  /* first time addition of the route */
126  *sixrd_domain_index,
127  &dpo_v4);
128 
129 route_add:
130  /*
131  * Create ip4 route. This is a reference counted add. If the prefix
132  * already exists and is SixRD sourced, it is now SixRD source n+1 times
133  * and will need to be removed n+1 times.
134  */
138  &dpo_v4);
139  dpo_reset (&dpo_v4);
140 
141  return 0;
142 }
143 
144 /*
145  * sixrd_delete_domain
146  */
147 int
148 sixrd_delete_domain (u32 sixrd_domain_index)
149 {
150  sixrd_main_t *mm = &sixrd_main;
151  sixrd_domain_t *d;
152 
153  if (pool_is_free_index(mm->domains, sixrd_domain_index)) {
154  clib_warning("SIXRD domain delete: domain does not exist: %d",
155  sixrd_domain_index);
156  return -1;
157  }
158 
159  d = pool_elt_at_index(mm->domains, sixrd_domain_index);
160 
161  fib_prefix_t pfx = {
163  .fp_len = 32,
164  .fp_addr = {
165  .ip4 = d->ip4_src,
166  },
167  };
169 
170  fib_prefix_t pfx6 = {
172  .fp_len = d->ip6_prefix_len,
173  .fp_addr = {
174  .ip6 = d->ip6_prefix,
175  },
176  };
178 
179  pool_put(mm->domains, d);
180 
181  return 0;
182 }
183 
184 static clib_error_t *
186  unformat_input_t *input,
187  vlib_cli_command_t *cmd)
188 {
189  unformat_input_t _line_input, *line_input = &_line_input;
190  ip4_address_t ip4_prefix;
191  ip6_address_t ip6_prefix;
192  ip4_address_t ip4_src;
193  u32 ip6_prefix_len=0, ip4_prefix_len=0, sixrd_domain_index;
194  u32 num_m_args = 0;
195  /* Optional arguments */
196  u32 mtu = 0;
197  clib_error_t *error = 0;
198 
199  /* Get a line of input. */
200  if (!unformat_user(input, unformat_line_input, line_input))
201  return 0;
202  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
203  if (unformat(line_input, "ip6-pfx %U/%d", unformat_ip6_address, &ip6_prefix, &ip6_prefix_len))
204  num_m_args++;
205  else if (unformat(line_input, "ip4-pfx %U/%d", unformat_ip4_address, &ip4_prefix, &ip4_prefix_len))
206  num_m_args++;
207  else if (unformat(line_input, "ip4-src %U", unformat_ip4_address, &ip4_src))
208  num_m_args++;
209  else if (unformat(line_input, "mtu %d", &mtu))
210  num_m_args++;
211  else {
212  error = clib_error_return(0, "unknown input `%U'",
213  format_unformat_error, line_input);
214  goto done;
215  }
216  }
217 
218  if (num_m_args < 3) {
219  error = clib_error_return(0, "mandatory argument(s) missing");
220  goto done;
221  }
222 
223  sixrd_create_domain(&ip6_prefix, ip6_prefix_len, &ip4_prefix, ip4_prefix_len,
224  &ip4_src, &sixrd_domain_index, mtu);
225 
226 done:
227  unformat_free (line_input);
228 
229  return error;
230 }
231 
232 static clib_error_t *
234  unformat_input_t *input,
235  vlib_cli_command_t *cmd)
236 {
237  unformat_input_t _line_input, *line_input = &_line_input;
238  u32 num_m_args = 0;
239  u32 sixrd_domain_index;
240  clib_error_t *error = 0;
241 
242  /* Get a line of input. */
243  if (! unformat_user(input, unformat_line_input, line_input))
244  return 0;
245 
246  while (unformat_check_input(line_input) != UNFORMAT_END_OF_INPUT) {
247  if (unformat(line_input, "index %d", &sixrd_domain_index))
248  num_m_args++;
249  else {
250  error = clib_error_return(0, "unknown input `%U'",
251  format_unformat_error, line_input);
252  goto done;
253  }
254  }
255 
256  if (num_m_args != 1) {
257  error = clib_error_return(0, "mandatory argument(s) missing");
258  goto done;
259  }
260 
261  sixrd_delete_domain(sixrd_domain_index);
262 
263 done:
264  unformat_free (line_input);
265 
266  return error;
267 }
268 
269 static u8 *
270 format_sixrd_domain (u8 *s, va_list *args)
271 {
272  sixrd_domain_t *d = va_arg(*args, sixrd_domain_t *);
273  sixrd_main_t *mm = &sixrd_main;
274 
275  s = format(s,
276  "[%d] ip6-pfx %U/%d ip4-pfx %U/%d ip4-src %U mtu %d",
277  d - mm->domains,
280  format_ip4_address, &d->ip4_src, d->mtu);
281 
282  return s;
283 }
284 
285 static clib_error_t *
287 {
288  sixrd_main_t *mm = &sixrd_main;
289  sixrd_domain_t *d;
290 
291  if (pool_elts(mm->domains) == 0)
292  vlib_cli_output(vm, "No SIXRD domains are configured...");
293 
294  pool_foreach(d, mm->domains, ({vlib_cli_output(vm, "%U", format_sixrd_domain, d);}));
295 
296  return 0;
297 
298 }
299 
300 static clib_error_t *
302 {
303  sixrd_main_t *mm = &sixrd_main;
304  sixrd_domain_t *d;
305  int domains = 0, domaincount = 0;
306  if (pool_elts (mm->domains) == 0)
307  vlib_cli_output (vm, "No SIXRD domains are configured...");
308 
309  pool_foreach(d, mm->domains, ({
310  domains += sizeof(*d);
311  domaincount++;
312  }));
313 
314  vlib_cli_output(vm, "SIXRD domains structure: %d\n", sizeof (sixrd_domain_t));
315  vlib_cli_output(vm, "SIXRD domains: %d (%d bytes)\n", domaincount, domains);
316 
317  return 0;
318 }
319 
320 /*
321  * packet trace format function
322  */
323 u8 *
324 format_sixrd_trace (u8 *s, va_list *args)
325 {
326  CLIB_UNUSED(vlib_main_t *vm) = va_arg (*args, vlib_main_t *);
327  CLIB_UNUSED(vlib_node_t *node) = va_arg (*args, vlib_node_t *);
328  sixrd_trace_t *t = va_arg (*args, sixrd_trace_t *);
329  u32 sixrd_domain_index = t->sixrd_domain_index;
330 
331  s = format(s, "SIXRD domain index: %d", sixrd_domain_index);
332 
333  return s;
334 }
335 
336 VLIB_CLI_COMMAND(sixrd_add_domain_command, static) = {
337  .path = "sixrd add domain",
338  .short_help =
339  "sixrd add domain ip6-pfx <ip6-pfx> ip4-pfx <ip4-pfx> ip4-src <ip4-addr>",
340  .function = sixrd_add_domain_command_fn,
341 };
342 
343 VLIB_CLI_COMMAND(sixrd_del_command, static) = {
344  .path = "sixrd del domain",
345  .short_help =
346  "sixrd del domain index <domain>",
347  .function = sixrd_del_domain_command_fn,
348 };
349 
350 VLIB_CLI_COMMAND(show_sixrd_domain_command, static) = {
351  .path = "show sixrd domain",
352  .function = show_sixrd_domain_command_fn,
353 };
354 
355 VLIB_CLI_COMMAND(show_sixrd_stats_command, static) = {
356  .path = "show sixrd stats",
357  .function = show_sixrd_stats_command_fn,
358 };
359 
360 /* *INDENT-OFF* */
362  .version = VPP_BUILD_VER,
363  .description = "IPv6 Rapid Deployment on IPv4 Infrastructure (RFC5969)",
364 };
365 /* *INDENT-ON* */
366 
368 {
369  sixrd_main_t *mm = &sixrd_main;
370 
371  mm->vnet_main = vnet_get_main();
372  mm->vlib_main = vm;
373 
375 
376  return (NULL);
377 }
378 
ip4_address_t ip4_src
Definition: sixrd.h:33
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:181
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:47
sixrd_main_t sixrd_main
Definition: sixrd.c:35
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:301
#define NULL
Definition: clib.h:55
static u8 * format_sixrd_domain(u8 *s, va_list *args)
Definition: sixrd.c:270
void dpo_copy(dpo_id_t *dst, const dpo_id_t *src)
atomic copy a data-plane object.
Definition: dpo.c:258
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:185
SIXRD.
Definition: fib_entry.h:86
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:438
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:172
#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:166
Definition: fib_entry.h:242
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:459
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:286
dpo_type_t dpoi_type
the type
Definition: dpo.h:170
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:233
struct _unformat_input_t unformat_input_t
load-balancing over a choice of [un]equal cost paths
Definition: dpo.h:102
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:271
static sixrd_dpo_t * sixrd_dpo_get(index_t index)
Definition: sixrd_dpo.h:54
const dpo_id_t * load_balance_get_bucket(index_t lbi, u32 bucket)
Definition: load_balance.c:294
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:148
#define clib_warning(format, args...)
Definition: error.h:59
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:29
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:268
#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:367
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:324
unsigned short u16
Definition: types.h:57
index_t dpoi_index
the index of objects of that type
Definition: dpo.h:182
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:30
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:38
#define DPO_INVALID
An initialiser for DPOs declared on the stack.
Definition: dpo.h:193
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:228
#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