aboutsummaryrefslogtreecommitdiffstats
path: root/hicn-plugin/src/punt.h
blob: 0e821ccb7a32b94a0c8b75a0ed0fb1aa33c8e4a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
/*
 * Copyright (c) 2017-2019 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __HICN_PUNT_H__
#define __HICN_PUNT_H__

#include <vppinfra/error.h>
#include <vnet/fib/fib_types.h>
#include "hicn.h"
#include <vnet/classify/vnet_classify.h>

#define HICN_CLASSIFY_TABLE_MEMORY_SIZE (2*1024*1024)	// 2MB allocated for the classification table
#define HICN_PUNTING_BUFFER_SIZE_32 (32)
#define HICN_PUNTING_BUFFER_SIZE_48 (48)
#define HICN_PUNTING_BUFFER_SIZE_64 (64)
#define HICN_PUNTING_BUFFER_SIZE_80 (80)
#define HICN_PUNTING_BUFFER_SIZE_128 (128)

/* Limits */

#define HICN_PUNT_IP4     0
#define HICN_PUNT_IP6     1

#define HICN_MAX_INTFC 256

/* We also consider mask = 0 to match everything */
#define HICN_PUNT_IP4_MASK   33
#define HICN_PUNT_IP6_MASK   129

#define HICN_PUNT_IP_TYPE 0
#define HICN_PUNT_UDP4_TYPE 1
#define HICN_PUNT_UDP6_TYPE 2

#define HICN_PUNT_INVALID_PORT 0
/*
 * u32 ip4_vnet_tbl_idx[HICN_MAX_INTFC][2][3][HICN_PUNT_IP4_MASK];
 * //[skip][src][mask],[skip][dst][mask] u32
 * ip6_vnet_tbl_idx[HICN_MAX_INTFC][2][3][HICN_PUNT_IP6_MASK];
 * //[skip][src][mask],[skip][dst][mask]
 */
#define PUNT_MASK(ip) (ip->addr_len_bits + 1)
#define TABLE_ELT_P(ip, i, j, k, l) (ip->tbl + (4 * 2 * PUNT_MASK(ip)) * i + (2 * PUNT_MASK(ip)) * j + k * PUNT_MASK(ip) + l)
#define TABLE_ELT(ip, i, j, k, l)  (*(TABLE_ELT_P(ip, i, j, k, l)))

#define NO_L2 0
#define ETH_L2 sizeof(ethernet_header_t)

#define IPPROTO_MASK 0xFF

/* Index to access vnet table index */
#define HICN_PUNT_SRC     0
#define HICN_PUNT_DST     1

#define HICN_PUNT_OK      0
#define HICN_PUNT_ERR     1

#define HICNP_PUNY_INVALID_TBL ~0

/* Number of bytes before the next header/protocol field in ip6/4 */
#define BYTES_TO_PROTOCOL_IP4 9
#define BYTES_TO_NEXT_HEADER_IP6 6

#define PUNT_BUFFER_SIZE 100	/* B */
#define CLASSIFIER_VECTOR_SIZE 16	/* B */

#define OP_DEL 0
#define OP_ADD 1
#define OP_DISABLE 0
#define OP_ENABLE 1

/* vnet_classify_add_del_table */
#define HICN_CLASSIFY_NO_NEXT_TABLE  0xFFFFFFFF
#define HICN_CLASSIFY_MISS_NEXT_INDEX 16
#define HICN_CLASSIFY_CURRENT_DATA_FLAG CLASSIFY_FLAG_USE_CURR_DATA
#define HICN_CLASSIFY_NO_CURRENT_DATA_FLAG 0
#define HICN_CLASSIFY_CURRENT_DATA_OFFSET 0
#define HICN_CLASSIFY_DON_T_DEL_CHAIN 0

/* vnet_classify_add_del_session */
#define HICN_CLASSIFY_OPAQUE_INDEX 0xFFFFFFFF
#define HICN_CLASSIFY_ADVANCE 0
#define HICN_CLASSIFY_ACTION 0
#define HICN_CLASSIFY_METADATA 0

/* This should be equal to the number of rules we expect in each table */
#define HICN_CLASSIFY_NBUCKETS 3


/* HICN punt node index */
typedef struct _hicn_node_info_s
{
  u32 hicn_face_ip4_input_index;
  u32 hicn_face_ip6_input_index;
  u32 hicn_iface_ip4_input_index;
  u32 hicn_iface_ip6_input_index;
  u32 hicn_face_ip4_output_index;
  u32 hicn_face_ip6_output_index;
  u32 hicn_iface_ip4_output_index;
  u32 hicn_iface_ip6_output_index;
  u32 hicn_face_udp4_input_index;
  u32 hicn_face_udp6_input_index;
  u32 hicn_iface_udp4_input_index;
  u32 hicn_iface_udp6_input_index;
  u32 hicn_face_udp4_output_index;
  u32 hicn_face_udp6_output_index;
  u32 hicn_iface_udp4_output_index;
  u32 hicn_iface_udp6_output_index;
  u32 ip4_inacl_node_index;
  u32 ip6_inacl_node_index;
  u32 ip4_lookup_node_index;
  u32 ip6_lookup_node_index;
} hicn_node_info_t;

/*
 * HICN global PUNT info
 */
typedef struct _hicn_punt_glb_s
{
  hicn_node_info_t hicn_node_info;

  /*
   * The following nodes are used to create the vlib node graph, and
   * point classified packets to the right node.
   */
  u32 next_hit_interest_ipv4;
  //node - graph index to forward packets to our hicn nodes
  u32 next_hit_data_ipv4;
  u32 next_hit_interest_ipv6;
  //node - graph index to forward packets to our hicn nodes
  u32 next_hit_data_ipv6;
  u32 next_hit_interest_udp4;
  //node - graph index to forward packets to our hicn nodes
  u32 next_hit_data_udp4;
  u32 next_hit_interest_udp6;
  //node - graph index to forward packets to our hicn nodes
  u32 next_hit_data_udp6;

  /*
   * One table is created : - per interface : so that we can have
   * different punted prefixes per interface, and thus decrease the
   * amount of matched rules per packet. An interface will be
   * consistently receiving packets with or without the ethernet
   * header, and thus the offsets should always be correct. - per skip
   * (assuming it is for the base offset (ethernet or not), in which
   * case the interface should be sufficient. - per prefix length to
   * allow for sorting later. - per src / dst (?)
   *
   * Note that there is no test on the packet type (v4 or v6), as they
   * follow distinct paths in the vpp graph and will thus be dispatched
   * to distinct classifiers. This is also why we duplicate the state
   * for both IPv4 and IPv6 in this implementation.
   *
   * Tables are chained per interface in the order they are added. Each
   * table consists in a set of rules (named sessions).
   *
   * / interface --> table i [.next_table_index=j] --> table j [.nti=~0]
   * -- drop \      |                                 | +-- on match,
   * send to node m      +-- [...] to node n
   *
   * For debugging purposes, you can use the following commands:
   *
   * vppctl show inacl type ip4 vppctl show inacl type ip6
   *
   * vppctl show classify tables [verbose]
   *
   * TODO: - allow tables to be removed - sort tables with decreasing
   * prefix length to allow for LPM. - directly access the linked list
   * through vpp APIs and remove global variables. They are not
   * sufficient anyways for removal.
   */

  /**
   * Given the current implementation, the following multidimensional array
   * stores the table indexes uniquerly identified by the 4-tuple (interface,
   * skip, src/dst, mask).
   *
   * For flexibility, some macros and functions will be defined in the .c to
   * manipulate this array.
   */
  u32 ip4_vnet_tbl_idx[HICN_MAX_INTFC][4][2][HICN_PUNT_IP4_MASK];
  //[skip][src][mask],[skip][dst][mask]
  u32 ip6_vnet_tbl_idx[HICN_MAX_INTFC][4][2][HICN_PUNT_IP6_MASK];
  //[skip][src][mask],[skip][dst][mask]
  u32 udp44_vnet_tbl_idx[HICN_MAX_INTFC][4][2][HICN_PUNT_IP4_MASK];
  //[skip][src][mask],[skip][dst][mask]
  u32 udp46_vnet_tbl_idx[HICN_MAX_INTFC][4][2][HICN_PUNT_IP6_MASK];
  //[skip][src][mask],[skip][dst][mask]
  u32 udp64_vnet_tbl_idx[HICN_MAX_INTFC][4][2][HICN_PUNT_IP4_MASK];
  //[skip][src][mask],[skip][dst][mask]
  u32 udp66_vnet_tbl_idx[HICN_MAX_INTFC][4][2][HICN_PUNT_IP6_MASK];
  //[skip][src][mask],[skip][dst][mask]

  /*
   * The first and last tables associated to each interface (both for
   * v4 and v6) are stored. They are respectively used to : - start
   * classification on the correct table depending on the input
   * interface: the assumption is that different interfaces with punt
   * different prefixes, which should decreate the number of potential
   * rules to match for each incoming packet. see.
   * vnet_set_input_acl_intfc() - maintain the chaining between tables
   * so that upon addition, the newly created table can be chained to
   * the previous last one.
   */
  u32 head_ip4[HICN_MAX_INTFC];
  u32 tail_ip4[HICN_MAX_INTFC];
  u32 head_ip6[HICN_MAX_INTFC];
  u32 tail_ip6[HICN_MAX_INTFC];

} hicn_punt_glb_t;

extern hicn_punt_glb_t hicn_punt_glb;



/* XXX The two following structs might be opaque */

#define NA 0

typedef struct
{
  u32 offset;
  u32 len;			/* bytes */
  u32 punt_id;			/* see explanation in hicn_punt.c */
} field_t;

/* Format: _(name, base, layer, field, punt_id) */
#define foreach_field                                            \
  _(ipv6_src, 0, _ipv6_header_t, saddr, HICN_PUNT_SRC)           \
  _(ipv6_dst, 0, _ipv6_header_t, daddr, HICN_PUNT_DST)           \
  _(ipv6_protocol, 0, _ipv6_header_t, nxt, NA)                   \
  _(ipv4_src, 0, _ipv4_header_t, saddr, HICN_PUNT_SRC)           \
  _(ipv4_dst, 0, _ipv4_header_t, daddr, HICN_PUNT_DST)           \
  _(ipv4_protocol, 0, _ipv4_header_t, protocol, NA)              \
                                                                 \
  _(ipv4_version, 0, _ipv4_header_t, version_ihl, NA)                   \
  _(ipv6_version, 0, _ipv6_header_t, vfc, NA)                           \
  _(udp4_sport, IPV4_HDRLEN, _udp_header_t, src_port, NA)               \
  _(udp4_dport, IPV4_HDRLEN, _udp_header_t, dst_port, NA)               \
  _(udp6_sport, IPV6_HDRLEN, _udp_header_t, src_port, NA)               \
  _(udp6_dport, IPV6_HDRLEN, _udp_header_t, dst_port, NA)               \
  _(udp6_protocol, 0, _ipv6_header_t, nxt, NA)				\
  _(udp4_protocol, 0, _ipv4_header_t, protocol, NA) \
  _(udp46_src, IPV4_HDRLEN + UDP_HDRLEN, _ipv6_header_t, saddr, HICN_PUNT_SRC) \
  _(udp46_dst, IPV4_HDRLEN + UDP_HDRLEN, _ipv6_header_t, daddr, HICN_PUNT_DST) \
  _(udp44_src, IPV4_HDRLEN + UDP_HDRLEN, _ipv4_header_t, saddr, HICN_PUNT_SRC) \
  _(udp44_dst, IPV4_HDRLEN + UDP_HDRLEN, _ipv4_header_t, daddr, HICN_PUNT_DST) \
  _(udp66_src, IPV6_HDRLEN + UDP_HDRLEN, _ipv6_header_t, saddr, HICN_PUNT_SRC) \
  _(udp66_dst, IPV6_HDRLEN + UDP_HDRLEN, _ipv6_header_t, daddr, HICN_PUNT_DST) \
  _(udp64_src, IPV6_HDRLEN + UDP_HDRLEN, _ipv6_header_t, saddr, HICN_PUNT_SRC) \
  _(udp64_dst, IPV6_HDRLEN + UDP_HDRLEN, _ipv6_header_t, daddr, HICN_PUNT_DST) \


#define _(NAME, BASE, LAYER, FIELD, PUNT_ID)          \
    extern field_t NAME;
foreach_field
#undef _
  typedef struct
{
  u32 *tbl;
  u8 addr_len_bits;
  field_t *protocol_field;
  field_t *version_field;
  field_t *udp_sport;
  field_t *udp_dport;
  u8 ip_version;
} ip_version_t;

extern ip_version_t ipv4;
extern ip_version_t ipv6;


/* ------------------------- */

/**
 * @brief Punt table APIs
 *
 * Those APIs are called when the first punting table is created for a given
 * interface, so as to point to the start of the chain.
 */
void
hicn_punt_enable_disable_vnet_ip4_table_on_intf (vlib_main_t * vm,
						 u32 sw_if_index,
						 int is_enable);
void
hicn_punt_enable_disable_vnet_ip6_table_on_intf (vlib_main_t * vm,
						 u32 sw_if_index,
						 int is_enable);
u32 hicn_punt_interest_data_for_udp (vlib_main_t * vm,
				     fib_prefix_t * prefix,
				     u32 swif, u8 punt_type, u16 sport,
				     u16 dport, u8 with_l2);
u32 hicn_punt_interest_data_for_ip (vlib_main_t * vm,
				    fib_prefix_t * prefix,
				    u32 swif, u8 type, u8 with_l2);
int hicn_punt_remove_ip6_address (vlib_main_t * vm, fib_prefix_t * prefix,
				  int skip, u32 swif, int is_enable,
				  u8 with_l2);
int hicn_punt_remove_ip4_address (vlib_main_t * vm, fib_prefix_t * prefix,
				  int skip, u32 swif, int is_enable,
				  u8 with_l2);
void hicn_punt_init (vlib_main_t * vm);

int
hicn_punt_add_del_vnettbl (ip_version_t * ip, field_t * field, u8 mask, u32
			   next_tbl_index, u32 intfc, u8 base_offset,
			   u8 use_current_data, int is_add);

#define hicn_punt_add_vnettbl(ip, field, mask, next_tbl_index, intfc, base_offset, use_current_data) \
  (hicn_punt_add_del_vnettbl(ip, field, mask, next_tbl_index, intfc, base_offset, use_current_data, OP_ADD))

#define hicn_punt_del_vnettbl(ip, field, mask, next_tbl_index, intfc, base_offset) \
  (hicn_punt_add_del_vnettbl(ip, field, mask, next_tbl_index, intfc, base_offset, HICN_CLASSIFY_NO_CURRENT_DATA_FLAG, OP_DEL))

int
hicn_punt_add_del_vnetssn (ip_version_t * ip, field_t * field,
			   fib_prefix_t * prefix,
			   u32 next_hit_index, u32 intfc, u8 base_offset,
			   int is_add);

#define hicn_punt_add_vnetssn(ip, field, addr, index, intfc, offset)    \
  (hicn_punt_add_del_vnetssn(ip, field, addr, index, intfc, offset, OP_ADD))

#define hicn_punt_del_vnetssn(ip, field, addr, index, intfc, offset)    \
    (hicn_punt_add_del_vnetssn(ip, field, addr, index, intfc, offset, OP_DEL))

#endif /* // __HICN_PUNT_H__ */

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables: eval: (c-set-style "gnu") End:
 */