FD.io VPP  v16.09
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 /*
20  * This code supports the following sixrd modes:
21  *
22  * 32 EA bits (Complete IPv4 address is embedded):
23  * ea_bits_len = 32
24  * IPv4 suffix is embedded:
25  * ea_bits_len = < 32
26  * No embedded address bits (1:1 mode):
27  * ea_bits_len = 0
28  */
29 
30 int
32  u8 ip6_prefix_len,
33  ip4_address_t *ip4_prefix,
34  u8 ip4_prefix_len,
35  ip4_address_t *ip4_src,
36  u32 *sixrd_domain_index,
37  u16 mtu)
38 {
39  sixrd_main_t *mm = &sixrd_main;
40  ip4_main_t *im4 = &ip4_main;
41  ip6_main_t *im6 = &ip6_main;
42  sixrd_domain_t *d;
43  ip_adjacency_t adj;
46  u32 *p;
47 
48  /* Get domain index */
50  memset(d, 0, sizeof (*d));
51  *sixrd_domain_index = d - mm->domains;
52 
53  /* Init domain struct */
54  d->ip4_prefix.as_u32 = ip4_prefix->as_u32;
55  d->ip4_prefix_len = ip4_prefix_len;
56  d->ip6_prefix = *ip6_prefix;
57  d->ip6_prefix_len = ip6_prefix_len;
58  d->ip4_src = *ip4_src;
59  d->mtu = mtu;
60 
61  if (ip4_prefix_len < 32)
62  d->shift = 64 - ip6_prefix_len + (32 - ip4_prefix_len);
63 
64  /* Init IP adjacency */
65  memset(&adj, 0, sizeof(adj));
66  adj.explicit_fib_index = ~0;
67  p = (u32 *)&adj.rewrite_data[0];
68  *p = (u32) (*sixrd_domain_index);
69 
70  /* Create ip6 adjacency */
71  memset(&args6, 0, sizeof(args6));
72  args6.table_index_or_table_id = 0;
73  args6.flags = IP6_ROUTE_FLAG_ADD;
74  args6.dst_address.as_u64[0] = ip6_prefix->as_u64[0];
75  args6.dst_address.as_u64[1] = ip6_prefix->as_u64[1];
76  args6.dst_address_length = ip6_prefix_len;
77  args6.adj_index = ~0;
78  args6.add_adj = &adj;
79  args6.n_add_adj = 1;
81  ip6_add_del_route(im6, &args6);
82 
83  /* Multiple SIXRD domains may share same source IPv4 TEP */
84  uword *q = ip4_get_route(im4, 0, 0, (u8 *)ip4_src, 32);
85  if (q) {
86  u32 ai = q[0];
88  ip_adjacency_t *adj4 = ip_get_adjacency(lm4, ai);
89  if (adj4->lookup_next_index != mm->ip4_lookup_next_index) {
90  clib_warning("BR source address already assigned: %U", format_ip4_address, ip4_src);
91  pool_put(mm->domains, d);
92  return -1;
93  }
94  /* Shared source */
95  p = (u32 *)&adj4->rewrite_data[0];
96  p[0] = ~0;
97 
98  /* Add refcount, so we don't accidentially delete the route underneath someone */
99  p[1]++;
100  } else {
101  /* Create ip4 adjacency. */
102  memset(&args4, 0, sizeof(args4));
103  args4.table_index_or_table_id = 0;
104  args4.flags = IP4_ROUTE_FLAG_ADD;
105  args4.dst_address.as_u32 = ip4_src->as_u32;
106  args4.dst_address_length = 32;
107  args4.adj_index = ~0;
108  args4.add_adj = &adj;
109  args4.n_add_adj = 1;
111  ip4_add_del_route(im4, &args4);
112  }
113 
114  return 0;
115 }
116 
117 /*
118  * sixrd_delete_domain
119  */
120 int
121 sixrd_delete_domain (u32 sixrd_domain_index)
122 {
123  sixrd_main_t *mm = &sixrd_main;
124  ip4_main_t *im4 = &ip4_main;
125  ip6_main_t *im6 = &ip6_main;
126  sixrd_domain_t *d;
127  ip_adjacency_t adj;
130 
131  if (pool_is_free_index(mm->domains, sixrd_domain_index)) {
132  clib_warning("SIXRD domain delete: domain does not exist: %d", sixrd_domain_index);
133  return -1;
134  }
135 
136  d = pool_elt_at_index(mm->domains, sixrd_domain_index);
137 
138  memset(&adj, 0, sizeof(adj));
139  adj.explicit_fib_index = ~0;
140 
141  /* Delete ip6 adjacency */
142  memset(&args6, 0, sizeof (args6));
143  args6.table_index_or_table_id = 0;
144  args6.flags = IP6_ROUTE_FLAG_DEL;
145  args6.dst_address.as_u64[0] = d->ip6_prefix.as_u64[0];
146  args6.dst_address.as_u64[1] = d->ip6_prefix.as_u64[1];
148  args6.adj_index = 0;
149  args6.add_adj = &adj;
150  args6.n_add_adj = 0;
151  ip6_add_del_route(im6, &args6);
152 
153  /* Delete ip4 adjacency */
154  uword *q = ip4_get_route(im4, 0, 0, (u8 *)&d->ip4_src, 32);
155  if (q) {
156  u32 ai = q[0];
158  ip_adjacency_t *adj4 = ip_get_adjacency(lm4, ai);
159 
160  u32 *p = (u32 *)&adj4->rewrite_data[0];
161  /* Delete route when no other domains use this source */
162  if (p[1] == 0) {
163  memset(&args4, 0, sizeof(args4));
164  args4.table_index_or_table_id = 0;
165  args4.flags = IP4_ROUTE_FLAG_DEL;
166  args4.dst_address.as_u32 = d->ip4_prefix.as_u32;
168  args4.adj_index = 0;
169  args4.add_adj = &adj;
170  args4.n_add_adj = 0;
171  ip4_add_del_route(im4, &args4);
172  }
173  p[1]--;
174  }
175 
176  pool_put(mm->domains, d);
177 
178  return 0;
179 }
180 
181 static clib_error_t *
183  unformat_input_t *input,
184  vlib_cli_command_t *cmd)
185 {
186  unformat_input_t _line_input, *line_input = &_line_input;
187  ip4_address_t ip4_prefix;
188  ip6_address_t ip6_prefix;
189  ip4_address_t ip4_src;
190  u32 ip6_prefix_len=0, ip4_prefix_len=0, sixrd_domain_index;
191  u32 num_m_args = 0;
192  /* Optional arguments */
193  u32 mtu = 0;
194 
195  /* Get a line of input. */
196  if (!unformat_user(input, unformat_line_input, line_input))
197  return 0;
198  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
199  if (unformat(line_input, "ip6-pfx %U/%d", unformat_ip6_address, &ip6_prefix, &ip6_prefix_len))
200  num_m_args++;
201  else if (unformat(line_input, "ip4-pfx %U/%d", unformat_ip4_address, &ip4_prefix, &ip4_prefix_len))
202  num_m_args++;
203  else if (unformat(line_input, "ip4-src %U", unformat_ip4_address, &ip4_src))
204  num_m_args++;
205  else if (unformat(line_input, "mtu %d", &mtu))
206  num_m_args++;
207  else
208  return clib_error_return(0, "unknown input `%U'",
209  format_unformat_error, input);
210  }
211  unformat_free(line_input);
212 
213  if (num_m_args < 3)
214  return clib_error_return(0, "mandatory argument(s) missing");
215 
216  sixrd_create_domain(&ip6_prefix, ip6_prefix_len, &ip4_prefix, ip4_prefix_len,
217  &ip4_src, &sixrd_domain_index, mtu);
218 
219  return 0;
220 }
221 
222 static clib_error_t *
224  unformat_input_t *input,
225  vlib_cli_command_t *cmd)
226 {
227  unformat_input_t _line_input, *line_input = &_line_input;
228  u32 num_m_args = 0;
229  u32 sixrd_domain_index;
230 
231  /* Get a line of input. */
232  if (! unformat_user(input, unformat_line_input, line_input))
233  return 0;
234 
235  while (unformat_check_input(line_input) != UNFORMAT_END_OF_INPUT) {
236  if (unformat(line_input, "index %d", &sixrd_domain_index))
237  num_m_args++;
238  else
239  return clib_error_return(0, "unknown input `%U'",
240  format_unformat_error, input);
241  }
242  unformat_free(line_input);
243 
244  if (num_m_args != 1)
245  return clib_error_return(0, "mandatory argument(s) missing");
246 
247  sixrd_delete_domain(sixrd_domain_index);
248 
249  return 0;
250 }
251 
252 static u8 *
253 format_sixrd_domain (u8 *s, va_list *args)
254 {
255  sixrd_domain_t *d = va_arg(*args, sixrd_domain_t *);
256  sixrd_main_t *mm = &sixrd_main;
257 
258  s = format(s,
259  "[%d] ip6-pfx %U/%d ip4-pfx %U/%d ip4-src %U mtu %d",
260  d - mm->domains,
263  format_ip4_address, &d->ip4_src, d->mtu);
264 
265  return s;
266 }
267 
268 static clib_error_t *
270 {
271  sixrd_main_t *mm = &sixrd_main;
272  sixrd_domain_t *d;
273 
274  if (pool_elts(mm->domains) == 0)
275  vlib_cli_output(vm, "No SIXRD domains are configured...");
276 
277  pool_foreach(d, mm->domains, ({vlib_cli_output(vm, "%U", format_sixrd_domain, d);}));
278 
279  return 0;
280 
281 }
282 
283 static clib_error_t *
285 {
286  sixrd_main_t *mm = &sixrd_main;
287  sixrd_domain_t *d;
288  int domains = 0, domaincount = 0;
289  if (pool_elts (mm->domains) == 0)
290  vlib_cli_output (vm, "No SIXRD domains are configured...");
291 
292  pool_foreach(d, mm->domains, ({
293  domains += sizeof(*d);
294  domaincount++;
295  }));
296 
297  vlib_cli_output(vm, "SIXRD domains structure: %d\n", sizeof (sixrd_domain_t));
298  vlib_cli_output(vm, "SIXRD domains: %d (%d bytes)\n", domaincount, domains);
299 
300  return 0;
301 }
302 
303 /*
304  * packet trace format function
305  */
306 u8 *
307 format_sixrd_trace (u8 *s, va_list *args)
308 {
309  CLIB_UNUSED(vlib_main_t *vm) = va_arg (*args, vlib_main_t *);
310  CLIB_UNUSED(vlib_node_t *node) = va_arg (*args, vlib_node_t *);
311  sixrd_trace_t *t = va_arg (*args, sixrd_trace_t *);
312  u32 sixrd_domain_index = t->sixrd_domain_index;
313 
314  s = format(s, "SIXRD domain index: %d", sixrd_domain_index);
315 
316  return s;
317 }
318 
319 VLIB_CLI_COMMAND(sixrd_add_domain_command, static) = {
320  .path = "sixrd add domain",
321  .short_help =
322  "sixrd add domain ip6-pfx <ip6-pfx> ip4-pfx <ip4-pfx> ip4-src <ip4-addr>",
323  .function = sixrd_add_domain_command_fn,
324 };
325 
326 VLIB_CLI_COMMAND(sixrd_del_command, static) = {
327  .path = "sixrd del domain",
328  .short_help =
329  "sixrd del domain index <domain>",
330  .function = sixrd_del_domain_command_fn,
331 };
332 
333 VLIB_CLI_COMMAND(show_sixrd_domain_command, static) = {
334  .path = "show sixrd domain",
335  .function = show_sixrd_domain_command_fn,
336 };
337 
338 VLIB_CLI_COMMAND(show_sixrd_stats_command, static) = {
339  .path = "show sixrd stats",
340  .function = show_sixrd_stats_command_fn,
341 };
342 
343 /*
344  * This routine exists to convince the vlib plugin framework that
345  * we haven't accidentally copied a random .dll into the plugin directory.
346  *
347  * Also collects global variable pointers passed from the vpp engine
348  */
349 clib_error_t *
351  int from_early_init)
352 {
353  clib_error_t * error = 0;
354  sixrd_main_t *mm = &sixrd_main;
355 
356  mm->vnet_main = vnet_get_main();
357  mm->vlib_main = vm;
358 
359  return error;
360 }
361 
363 {
364  clib_error_t * error = 0;
365  sixrd_main_t *mm = &sixrd_main;
366 
367  vlib_node_t * ip6_lookup_node = vlib_get_node_by_name(vm, (u8 *)"ip6-lookup");
368  vlib_node_t * ip4_lookup_node = vlib_get_node_by_name(vm, (u8 *)"ip4-lookup");
369  vlib_node_t * ip6_sixrd_node = vlib_get_node_by_name(vm, (u8 *)"ip6-sixrd");
370  vlib_node_t * ip4_sixrd_node = vlib_get_node_by_name(vm, (u8 *)"ip4-sixrd");
371  ASSERT(ip6_lookup_node && ip4_lookup_node && ip6_sixrd_node && ip4_sixrd_node);
372 
373  mm->ip6_lookup_next_index = vlib_node_add_next(vm, ip6_lookup_node->index, ip6_sixrd_node->index);
374  mm->ip4_lookup_next_index = vlib_node_add_next(vm, ip4_lookup_node->index, ip4_sixrd_node->index);
375 
376  return error;
377 }
378 
ip4_address_t ip4_src
Definition: sixrd.h:30
vlib_main_t * vlib_main
Definition: sixrd.h:45
#define CLIB_UNUSED(x)
Definition: clib.h:79
static vlib_node_registration_t ip4_sixrd_node
(constructor) VLIB_REGISTER_NODE (ip4_sixrd_node)
Definition: ip4_sixrd.c:18
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
format_function_t format_ip6_address
Definition: format.h:87
ip_lookup_next_t lookup_next_index
Definition: lookup.h:180
u64 as_u64[2]
Definition: ip6_packet.h:50
IP unicast adjacency.
Definition: lookup.h:164
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:284
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
u32 index
Definition: node.h:237
static u8 * format_sixrd_domain(u8 *s, va_list *args)
Definition: sixrd.c:253
ip_lookup_main_t lookup_main
Definition: ip4.h:115
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:182
format_function_t format_ip4_address
Definition: format.h:71
static uword vlib_node_add_next(vlib_main_t *vm, uword node, uword next_node)
Definition: node_funcs.h:1061
vlib_node_registration_t ip4_lookup_node
(constructor) VLIB_REGISTER_NODE (ip4_lookup_node)
Definition: ip4_forward.c:1541
u8 ip4_prefix_len
Definition: sixrd.h:32
vnet_main_t * vnet_get_main(void)
Definition: misc.c:45
u32 ip4_lookup_next_index
Definition: sixrd.h:48
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:348
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
vnet_main_t * vnet_main
Definition: sixrd.h:46
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
#define clib_warning(format, args...)
Definition: error.h:59
u32 table_index_or_table_id
Definition: ip6.h:367
ip4_address_t ip4_prefix
Definition: sixrd.h:29
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:977
void ip6_add_del_route(ip6_main_t *im, ip6_add_del_route_args_t *args)
Definition: ip6_forward.c:208
unformat_function_t unformat_ip4_address
Definition: format.h:68
ip6_address_t dst_address
Definition: ip6.h:370
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:369
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:269
clib_error_t * vlib_plugin_register(vlib_main_t *vm, vnet_plugin_handoff_t *h, int from_early_init)
Definition: sixrd.c:350
void * ip4_get_route(ip4_main_t *im, u32 fib_index_or_table_id, u32 flags, u8 *address, u32 address_length)
Definition: ip4_forward.c:537
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:223
ip_adjacency_t * add_adj
Definition: ip6.h:379
static vlib_node_registration_t ip6_sixrd_node
(constructor) VLIB_REGISTER_NODE (ip6_sixrd_node)
Definition: ip6_sixrd.c:23
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:214
sixrd_main_t sixrd_main
Definition: sixrd.h:82
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:575
unformat_function_t unformat_ip6_address
Definition: format.h:86
ip_adjacency_t * add_adj
Definition: ip4.h:337
#define pool_get_aligned(P, E, A)
Allocate an object E from a pool P (general version).
Definition: pool.h:169
int sixrd_delete_domain(u32 sixrd_domain_index)
Definition: sixrd.c:121
#define IP6_ROUTE_FLAG_DEL
Definition: ip6.h:352
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:211
#define IP4_ROUTE_FLAG_DEL
Definition: ip4.h:309
vlib_node_registration_t ip6_lookup_node
(constructor) VLIB_REGISTER_NODE (ip6_lookup_node)
Definition: ip6_forward.c:1381
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
ip4_address_t dst_address
Definition: ip4.h:328
#define IP4_ROUTE_FLAG_ADD
Definition: ip4.h:308
ip6_main_t ip6_main
Definition: ip6_forward.c:2955
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:418
IPv4 main type.
Definition: ip4.h:114
ip6_address_t ip6_prefix
Definition: sixrd.h:28
static clib_error_t * sixrd_init(vlib_main_t *vm)
Definition: sixrd.c:362
sixrd_domain_t * domains
Definition: sixrd.h:42
u64 uword
Definition: types.h:112
u32 sixrd_domain_index
Definition: sixrd.h:79
vlib_node_t * vlib_get_node_by_name(vlib_main_t *vm, u8 *name)
Definition: node.c:45
u8 * format_sixrd_trace(u8 *s, va_list *args)
Definition: sixrd.c:307
unsigned short u16
Definition: types.h:57
VLIB_CLI_COMMAND(set_interface_ip_source_and_port_range_check_command, static)
unsigned char u8
Definition: types.h:56
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:31
u32 table_index_or_table_id
Definition: ip4.h:325
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
u8 ip6_prefix_len
Definition: sixrd.h:31
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1578
#define IP6_ROUTE_FLAG_ADD
Definition: ip6.h:351
i16 explicit_fib_index
Force re-lookup in a different FIB.
Definition: lookup.h:185
#define clib_error_return(e, args...)
Definition: error.h:111
struct _unformat_input_t unformat_input_t
void ip4_add_del_route(ip4_main_t *im, ip4_add_del_route_args_t *args)
Definition: ip4_forward.c:228
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
unformat_function_t unformat_line_input
Definition: format.h:281
u32 ip6_lookup_next_index
Definition: sixrd.h:49
static ip_adjacency_t * ip_get_adjacency(ip_lookup_main_t *lm, u32 adj_index)
Definition: lookup.h:480
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:109