Line data Source code
1 : /*
2 : * vr_flow.c -- flow handling
3 : *
4 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
5 : */
6 : #include <vr_os.h>
7 : #include <vr_types.h>
8 : #include <vrouter.h>
9 : #include <vr_packet.h>
10 : #include <vr_htable.h>
11 : #include <vr_flow.h>
12 : #include <vr_mirror.h>
13 : #include "vr_interface.h"
14 : #include "vr_sandesh.h"
15 : #include "vr_message.h"
16 : #include "vr_btable.h"
17 : #include "vr_fragment.h"
18 : #include "vr_datapath.h"
19 : #include "vr_hash.h"
20 : #include "vr_ip_mtrie.h"
21 : #include "vr_bridge.h"
22 : #include "vr_vrf_table.h"
23 : #include "vr_nexthop.h"
24 :
25 : #include "vr_offloads_dp.h"
26 :
27 : #define VR_NUM_FLOW_TABLES 1
28 :
29 : #define VR_NUM_OFLOW_TABLES 1
30 :
31 : #define VR_DEF_MAX_FLOW_TABLE_HOLD_COUNT 8192
32 :
33 : unsigned int vr_flow_entries = VR_DEF_FLOW_ENTRIES;
34 : unsigned int vr_oflow_entries = 0;
35 : /*
36 : * Knob to unconditionally close flow on TCP RST;
37 : * If this knob is set, the flow would be closed
38 : * on receiving a TCP RST without doing any seqnum
39 : * validation (for backward compatibility with older
40 : * implementation);
41 : * If this knob is off, TCP RST seqnum validation
42 : * as per RFC 5961 sec 3.2 will be done. If the
43 : * validation fails, the RST will be ignored.
44 : * By default the knob is off;
45 : */
46 : unsigned int vr_uncond_close_flow_on_tcp_rst = 0;
47 :
48 : /*
49 : * host can provide its own memory . Point in case is the DPDK. In DPDK,
50 : * we allocate the table from hugepages and just ask the flow module to
51 : * use those tables
52 : */
53 : void *vr_flow_table = NULL;
54 : void *vr_oflow_table = NULL;
55 : /*
56 : * The flow table memory can also be a file that could be mapped. The path
57 : * is set by somebody and passed to agent for it to map
58 : */
59 : unsigned char *vr_flow_path;
60 : unsigned int vr_flow_hold_limit = VR_DEF_MAX_FLOW_TABLE_HOLD_COUNT;
61 :
62 : #if defined(__linux__) && defined(__KERNEL__)
63 : extern short vr_flow_major;
64 : #endif
65 :
66 : void vr_flow_defer_cb(struct vrouter *router, void *arg);
67 :
68 : uint32_t vr_hashrnd = 0;
69 : int hashrnd_inited = 0;
70 :
71 109 : static struct vr_flow_entry *vr_flow_bucket_first_entry(struct vrouter *router, struct vr_flow *key) {
72 109 : return (struct vr_flow_entry*)
73 109 : vr_htable_get_bucket(router->vr_flow_table, key, key->flow_key_len);
74 : }
75 :
76 : /*
77 : * The vr_flow_bucket_lock and vr_flow_bucket_unlock callbacks may not be
78 : * implemented for all instances of host_os. Those callback are needed only for
79 : * implementations that require strict race condition controll for
80 : * hardware offloading (like DPDK).
81 : * Those helper functions call the locks only when they are available.
82 : */
83 109 : static void vr_flow_bucket_may_lock(struct vr_flow_entry *fe) {
84 109 : if (vr_flow_bucket_lock && vr_flow_bucket_unlock)
85 109 : vr_flow_bucket_lock(fe);
86 109 : }
87 :
88 109 : static void vr_flow_bucket_may_unlock(struct vr_flow_entry *fe) {
89 109 : if (vr_flow_bucket_lock && vr_flow_bucket_unlock)
90 109 : vr_flow_bucket_unlock(fe);
91 109 : }
92 :
93 : static void vr_flush_entry(struct vrouter *, struct vr_flow_entry *,
94 : struct vr_flow_md *, struct vr_forwarding_md *);
95 : static void __vr_flow_flush_hold_queue(struct vrouter *, struct vr_flow_entry *,
96 : struct vr_forwarding_md *, struct vr_flow_queue *);
97 : static void vr_flow_set_forwarding_md(struct vrouter *, struct vr_flow_entry *,
98 : unsigned int, struct vr_forwarding_md *);
99 : static int
100 : __vr_flow_schedule_transition(struct vrouter *, struct vr_flow_entry *,
101 : unsigned int, unsigned short);
102 : static bool vr_flow_is_fat_flow(struct vrouter *, struct vr_packet *,
103 : struct vr_flow_entry *);
104 :
105 : struct vr_flow_entry *vr_find_flow(struct vrouter *, struct vr_flow *,
106 : uint8_t, unsigned int *);
107 : unsigned int vr_trap_flow(struct vrouter *, struct vr_flow_entry *,
108 : struct vr_packet *, unsigned int, struct vr_flow_stats *,
109 : struct vr_packet_node *);
110 : extern struct vr_nexthop *vr_inet_ip_lookup(unsigned short, uint32_t);
111 : extern struct vr_nexthop *vr_inet6_ip_lookup(unsigned short, uint8_t *);
112 :
113 : bool
114 1 : vr_valid_link_local_port(struct vrouter *router, int family,
115 : int proto, int port)
116 : {
117 : unsigned char data;
118 : unsigned int tmp;
119 :
120 1 : if (!router->vr_link_local_ports)
121 0 : return false;
122 :
123 1 : if ((family != AF_INET) ||
124 1 : ((proto != VR_IP_PROTO_TCP) && (proto != VR_IP_PROTO_UDP) &&
125 : (proto != VR_IP_PROTO_ICMP)))
126 0 : return false;
127 :
128 1 : if ((port < VR_DYNAMIC_PORT_START) || (port > VR_DYNAMIC_PORT_END))
129 0 : return false;
130 :
131 1 : tmp = port - VR_DYNAMIC_PORT_START;
132 1 : if (proto == VR_IP_PROTO_UDP)
133 1 : tmp += (router->vr_link_local_ports_size * 8 / VR_LL_RP_MAX);
134 1 : if (proto == VR_IP_PROTO_ICMP)
135 0 : tmp += (router->vr_link_local_ports_size * 8 * VR_LL_RP_ICMP_INDEX /
136 : VR_LL_RP_MAX);
137 :
138 1 : data = router->vr_link_local_ports[(tmp / 8)];
139 1 : if (data & (1 << (tmp % 8)))
140 1 : return true;
141 :
142 0 : return false;
143 : }
144 :
145 : static void
146 3 : vr_clear_link_local_port(struct vrouter *router, int family,
147 : int proto, int port)
148 : {
149 : unsigned char *data;
150 : unsigned int tmp;
151 :
152 3 : if (!router->vr_link_local_ports)
153 0 : return;
154 :
155 3 : if ((family != AF_INET) ||
156 3 : ((proto != VR_IP_PROTO_TCP) && (proto != VR_IP_PROTO_UDP) &&
157 : (proto != VR_IP_PROTO_ICMP)))
158 0 : return;
159 :
160 3 : if ((port < VR_DYNAMIC_PORT_START) || (port > VR_DYNAMIC_PORT_END))
161 0 : return;
162 :
163 3 : tmp = port - VR_DYNAMIC_PORT_START;
164 3 : if (proto == VR_IP_PROTO_UDP)
165 2 : tmp += (router->vr_link_local_ports_size * 8 / VR_LL_RP_MAX);
166 3 : if (proto == VR_IP_PROTO_ICMP)
167 1 : tmp += ((router->vr_link_local_ports_size * 8 * VR_LL_RP_ICMP_INDEX)/
168 : VR_LL_RP_MAX);
169 :
170 3 : data = &router->vr_link_local_ports[(tmp / 8)];
171 3 : *data &= (~(1 << (tmp % 8)));
172 :
173 3 : return;
174 : }
175 :
176 : static void
177 2 : vr_set_link_local_port(struct vrouter *router, int family,
178 : int proto, int port)
179 : {
180 : unsigned char *data;
181 : unsigned int tmp;
182 :
183 2 : if (!router->vr_link_local_ports)
184 0 : return;
185 :
186 2 : if ((family != AF_INET) ||
187 2 : ((proto != VR_IP_PROTO_TCP) && (proto != VR_IP_PROTO_UDP) &&
188 : (proto != VR_IP_PROTO_ICMP)))
189 0 : return;
190 :
191 2 : if ((port < VR_DYNAMIC_PORT_START) || (port > VR_DYNAMIC_PORT_END))
192 0 : return;
193 :
194 2 : tmp = port - VR_DYNAMIC_PORT_START;
195 2 : if (proto == VR_IP_PROTO_UDP)
196 1 : tmp += (router->vr_link_local_ports_size * 8 / VR_LL_RP_MAX);
197 2 : if (proto == VR_IP_PROTO_ICMP)
198 1 : tmp += ((router->vr_link_local_ports_size * 8 * VR_LL_RP_ICMP_INDEX)/
199 : VR_LL_RP_MAX);
200 :
201 2 : data = &router->vr_link_local_ports[tmp / 8];
202 2 : *data |= (1 << (tmp % 8));
203 :
204 2 : return;
205 : }
206 :
207 : static void
208 215 : vr_flow_reset_mirror(struct vrouter *router, struct vr_flow_entry *fe,
209 : unsigned int index)
210 : {
211 215 : if (fe->fe_flags & VR_FLOW_FLAG_MIRROR) {
212 2 : fe->fe_mirror_id = VR_MAX_MIRROR_INDICES;
213 2 : fe->fe_sec_mirror_id = VR_MAX_MIRROR_INDICES;
214 2 : if (fe->fe_mme) {
215 0 : vr_mirror_meta_entry_del(router, fe->fe_mme);
216 0 : fe->fe_mme = NULL;
217 0 : vr_offload_flow_meta_data_set(index, 0, 0, 0);
218 : }
219 : }
220 215 : fe->fe_flags &= ~VR_FLOW_FLAG_MIRROR;
221 215 : fe->fe_mirror_id = VR_MAX_MIRROR_INDICES;
222 215 : fe->fe_sec_mirror_id = VR_MAX_MIRROR_INDICES;
223 :
224 215 : return;
225 : }
226 :
227 : static void
228 109 : vr_init_flow_entry(struct vr_flow_entry *fe)
229 : {
230 109 : fe->fe_rflow = -1;
231 109 : fe->fe_mirror_id = VR_MAX_MIRROR_INDICES;
232 109 : fe->fe_sec_mirror_id = VR_MAX_MIRROR_INDICES;
233 109 : fe->fe_ecmp_nh_index = -1;
234 :
235 109 : return;
236 : }
237 :
238 :
239 : static void
240 117 : __vr_flow_reset_entry(struct vrouter *router, struct vr_flow_entry *fe)
241 : {
242 117 : if (fe->fe_hold_list) {
243 0 : vr_printf("vrouter: Potential memory leak @ %s:%d\n",
244 : __FILE__, __LINE__);
245 : }
246 117 : fe->fe_hold_list = NULL;
247 117 : fe->fe_key.flow_key_len = 0;
248 :
249 117 : (void)vr_offload_flow_del(fe);
250 :
251 117 : vr_flow_reset_mirror(router, fe, fe->fe_hentry.hentry_index);
252 117 : fe->fe_ecmp_nh_index = -1;
253 117 : fe->fe_src_nh_index = NH_DISCARD_ID;
254 117 : fe->fe_rflow = -1;
255 117 : fe->fe_action = VR_FLOW_ACTION_DROP;
256 117 : fe->fe_udp_src_port = 0;
257 117 : fe->fe_tcp_flags = 0;
258 117 : fe->fe_flags &=
259 : (VR_FLOW_FLAG_ACTIVE | VR_FLOW_FLAG_EVICTED |
260 : VR_FLOW_FLAG_NEW_FLOW | VR_FLOW_FLAG_DELETE_MARKED);
261 117 : fe->fe_flags1 &=
262 : ~(VR_FLOW_FLAG1_HBS_LEFT | VR_FLOW_FLAG1_HBS_RIGHT);
263 117 : fe->fe_ttl = 0;
264 117 : fe->fe_underlay_ecmp_index = -1;
265 117 : fe->fe_src_info = 0;
266 :
267 117 : return;
268 : }
269 :
270 : static void
271 109 : vr_flow_reset_entry(struct vrouter *router, struct vr_flow_entry *fe)
272 : {
273 109 : __vr_flow_reset_entry(router, fe);
274 109 : memset(&fe->fe_stats, 0, sizeof(fe->fe_stats));
275 109 : fe->fe_type = VP_TYPE_NULL;
276 109 : fe->fe_flags = 0;
277 :
278 109 : vr_htable_release_hentry(router->vr_flow_table, &fe->fe_hentry);
279 109 : return;
280 : }
281 :
282 : static void
283 8 : vr_flow_reset_active_entry(struct vrouter *router, struct vr_flow_entry *fe)
284 : {
285 8 : __vr_flow_reset_entry(router, fe);
286 8 : vr_htable_release_hentry(router->vr_flow_table, &fe->fe_hentry);
287 8 : return;
288 : }
289 :
290 :
291 : static vr_hentry_key
292 62 : vr_flow_get_key(vr_htable_t flow_table, vr_hentry_t *entry,
293 : unsigned int *key_len)
294 : {
295 62 : struct vr_flow_entry *fe = CONTAINER_OF(fe_hentry,
296 : struct vr_flow_entry, entry);
297 :
298 62 : if ((fe->fe_flags & VR_FLOW_FLAG_DELETE_MARKED) ||
299 62 : !(fe->fe_flags & VR_FLOW_FLAG_ACTIVE))
300 0 : return NULL;
301 :
302 62 : if (key_len)
303 62 : *key_len = fe->fe_key.flow_key_len;
304 :
305 62 : return &fe->fe_key;
306 : }
307 :
308 : uint32_t
309 1 : vr_flow_get_rflow_src_info(struct vrouter *router,
310 : struct vr_flow_entry *fe)
311 : {
312 : struct vr_flow_entry *rfe;
313 :
314 1 : if ((!fe) || !(fe->fe_flags & VR_RFLOW_VALID))
315 0 : return (unsigned int)-1;
316 :
317 1 : rfe = vr_flow_get_entry(router, fe->fe_rflow);
318 1 : if (!rfe)
319 0 : return (unsigned int)-1;
320 :
321 1 : return rfe->fe_src_info;
322 : }
323 :
324 : static inline bool
325 109 : vr_flow_set_active(struct vr_flow_entry *fe)
326 : {
327 109 : return vr_sync_bool_compare_and_swap_16u(&fe->fe_flags,
328 : fe->fe_flags & ~VR_FLOW_FLAG_ACTIVE,
329 : VR_FLOW_FLAG_ACTIVE | VR_FLOW_FLAG_NEW_FLOW);
330 : }
331 :
332 : /*
333 : * This api is called to get flow table size
334 : * NOTE: This api is also called from agent (via sandesh)
335 : * very early during init even before flow table is
336 : * initialized to calculate huge page table size.
337 : * Hence this api should not use vr_htable structures
338 : */
339 : unsigned int
340 13 : vr_flow_table_size(struct vrouter *router)
341 : {
342 : // set the overlflow flow table entries
343 13 : vr_compute_size_oflow_table();
344 13 : return (VR_FLOW_TABLE_SIZE + VR_OFLOW_TABLE_SIZE);
345 : }
346 :
347 : unsigned int
348 13 : vr_flow_table_used_oflow_entries(struct vrouter *router)
349 : {
350 13 : return vr_htable_used_oflow_entries(router->vr_flow_table);
351 : }
352 :
353 : unsigned int
354 13 : vr_flow_table_used_total_entries(struct vrouter *router)
355 : {
356 13 : return vr_htable_used_total_entries(router->vr_flow_table);
357 : }
358 : /*
359 : * this is used by the mmap code. mmap sees the whole flow table
360 : * (including the overflow table) as one large table. so, given
361 : * an offset into that large memory, we should return the correct
362 : * virtual address
363 : */
364 : void *
365 0 : vr_flow_get_va(struct vrouter *router, uint64_t offset)
366 : {
367 0 : return vr_htable_get_address(router->vr_flow_table, offset);
368 : }
369 :
370 : struct vr_flow_entry *
371 1236 : vr_flow_get_entry(struct vrouter *router, int index)
372 : {
373 1236 : if (index < 0)
374 104 : return NULL;
375 :
376 1132 : return (struct vr_flow_entry *)
377 1132 : vr_htable_get_hentry_by_index(router->vr_flow_table, index);
378 : }
379 :
380 : static inline void
381 120 : vr_flow_stop_modify(struct vrouter *router, struct vr_flow_entry *fe)
382 : {
383 120 : if (!fe)
384 0 : return;
385 :
386 120 : (void)vr_sync_and_and_fetch_16u(&fe->fe_flags, ~VR_FLOW_FLAG_MODIFIED);
387 120 : return;
388 : }
389 :
390 : static inline bool
391 222 : vr_flow_start_modify(struct vrouter *router, struct vr_flow_entry *fe)
392 : {
393 : unsigned short flags;
394 :
395 222 : flags = fe->fe_flags;
396 222 : if (!(flags & (VR_FLOW_FLAG_MODIFIED | VR_FLOW_FLAG_EVICTED |
397 : VR_FLOW_FLAG_NEW_FLOW))) {
398 218 : if (vr_sync_bool_compare_and_swap_16u(&fe->fe_flags, flags,
399 : flags | VR_FLOW_FLAG_MODIFIED)) {
400 218 : return true;
401 : }
402 : }
403 :
404 4 : return false;
405 : }
406 :
407 :
408 : /* Non-static due to RCU callback pointer comparison in vRouter/DPDK */
409 : static void
410 2 : vr_flow_flush_hold_queue(struct vrouter *router, struct vr_flow_entry *fe,
411 : struct vr_flow_queue *vfq)
412 : {
413 : struct vr_forwarding_md fmd;
414 :
415 2 : if (vfq) {
416 2 : vr_init_forwarding_md(&fmd);
417 2 : vr_flow_set_forwarding_md(router, fe, vfq->vfq_index, &fmd);
418 2 : __vr_flow_flush_hold_queue(router, fe, &fmd, vfq);
419 : }
420 :
421 2 : return;
422 : }
423 :
424 : static void
425 8 : vr_flow_evict_flow(struct vrouter *router, struct vr_flow_entry *fe)
426 : {
427 : unsigned short flags;
428 :
429 8 : if (!fe)
430 0 : return;
431 :
432 8 : if ((fe->fe_flags & VR_FLOW_FLAG_ACTIVE) &&
433 8 : (fe->fe_flags & VR_FLOW_FLAG_EVICT_CANDIDATE)) {
434 8 : flags = fe->fe_flags | VR_FLOW_FLAG_ACTIVE |
435 : VR_FLOW_FLAG_EVICT_CANDIDATE;
436 8 : if (vr_sync_bool_compare_and_swap_16u(&fe->fe_flags, flags,
437 : (flags ^ VR_FLOW_FLAG_EVICT_CANDIDATE) |
438 : VR_FLOW_FLAG_EVICTED)) {
439 8 : vr_flow_stop_modify(router, fe);
440 8 : vr_flow_reset_active_entry(router, fe);
441 : }
442 : }
443 :
444 8 : return;
445 : }
446 :
447 : void
448 6 : vr_flow_defer_cb(struct vrouter *router, void *arg)
449 : {
450 : struct vr_defer_data *defer;
451 : struct vr_flow_entry *fe, *rfe;
452 : struct vr_flow_queue *vfq;
453 : struct vr_flow_defer_data *vfdd;
454 :
455 6 : defer = (struct vr_defer_data *)arg;
456 6 : if (!defer)
457 0 : return;
458 :
459 6 : vfdd = (struct vr_flow_defer_data *)defer->vdd_data;
460 6 : if (!vfdd)
461 0 : return;
462 6 : fe = vfdd->vfdd_fe;
463 :
464 6 : vfq = (struct vr_flow_queue *)vfdd->vfdd_flow_queue;
465 6 : if (vfq) {
466 2 : vr_flow_flush_hold_queue(router, fe, vfq);
467 2 : vr_free(vfq, VR_FLOW_QUEUE_OBJECT);
468 2 : vfdd->vfdd_flow_queue = NULL;
469 : }
470 :
471 6 : if (vfdd->vfdd_delete) {
472 0 : vr_flow_reset_entry(router, fe);
473 6 : } else if (vfdd->vfdd_evict_flow) {
474 4 : rfe = vr_flow_get_entry(router, fe->fe_rflow);
475 4 : vr_flow_evict_flow(router, fe);
476 4 : if (rfe)
477 4 : vr_flow_evict_flow(router, rfe);
478 : }
479 :
480 6 : vr_free(vfdd, VR_FLOW_DEFER_DATA_OBJECT);
481 :
482 6 : return;
483 : }
484 :
485 : static void
486 0 : vr_flow_reset_evict(struct vrouter *router, struct vr_flow_entry *fe)
487 : {
488 : unsigned short flags;
489 :
490 0 : if (!fe)
491 0 : return;
492 :
493 0 : flags = fe->fe_flags;
494 0 : if (flags & VR_FLOW_FLAG_EVICT_CANDIDATE) {
495 0 : (void)vr_sync_bool_compare_and_swap_16u(&fe->fe_flags, flags,
496 : (flags ^ VR_FLOW_FLAG_EVICT_CANDIDATE));
497 : }
498 :
499 0 : vr_flow_stop_modify(router, fe);
500 :
501 0 : return;
502 : }
503 :
504 : static void
505 318 : vr_flow_defer(struct vr_flow_md *flmd, struct vr_flow_entry *fe)
506 : {
507 : struct vr_flow_entry *rfe;
508 318 : struct vr_defer_data *vdd = flmd->flmd_defer_data;
509 : struct vr_flow_defer_data *vfdd;
510 :
511 318 : if (!vdd || !vdd->vdd_data) {
512 312 : if (flmd->flmd_flags & VR_FLOW_FLAG_EVICT_CANDIDATE) {
513 0 : if (fe->fe_rflow) {
514 0 : rfe = vr_flow_get_entry(flmd->flmd_router, fe->fe_rflow);
515 0 : vr_flow_reset_evict(flmd->flmd_router, rfe);
516 : }
517 0 : vr_flow_reset_evict(flmd->flmd_router, fe);
518 : }
519 :
520 312 : if (!(flmd->flmd_flags & VR_FLOW_FLAG_ACTIVE)) {
521 98 : vr_flow_reset_entry(flmd->flmd_router, fe);
522 : }
523 :
524 312 : return;
525 : }
526 :
527 6 : vfdd = (struct vr_flow_defer_data *)vdd->vdd_data;
528 6 : vfdd->vfdd_fe = fe;
529 :
530 6 : vr_defer(flmd->flmd_router, vr_flow_defer_cb, (void *)vdd);
531 6 : flmd->flmd_defer_data = NULL;
532 :
533 6 : return;
534 : }
535 :
536 : static struct vr_flow_entry *
537 109 : vr_flow_table_get_free_entry(struct vrouter *router, struct vr_flow *key,
538 : unsigned int *free_index)
539 : {
540 : unsigned short flags;
541 : struct vr_flow_entry *fe;
542 :
543 : fe = (struct vr_flow_entry *)
544 109 : vr_htable_find_free_hentry(router->vr_flow_table, key,
545 109 : key->flow_key_len);
546 109 : if (fe) {
547 109 : flags = fe->fe_flags;
548 109 : if (!(flags & VR_FLOW_FLAG_ACTIVE)) {
549 109 : if (vr_flow_set_active(fe)) {
550 109 : vr_init_flow_entry(fe);
551 : }
552 0 : } else if (flags & VR_FLOW_FLAG_EVICTED) {
553 0 : fe->fe_flags = ((flags & ~VR_FLOW_FLAG_EVICTED) |
554 : VR_FLOW_FLAG_NEW_FLOW);
555 : }
556 :
557 109 : fe->fe_underlay_ecmp_index = -1;
558 :
559 109 : fe->fe_gen_id = (fe->fe_gen_id + 1) %
560 : (1 << (8 * sizeof(fe->fe_gen_id)));
561 109 : *free_index = fe->fe_hentry.hentry_index;
562 : }
563 :
564 109 : return fe;
565 : }
566 :
567 :
568 : static struct vr_flow_entry *
569 109 : vr_flow_get_free_entry(struct vrouter *router, struct vr_flow *key, uint8_t type,
570 : bool need_hold, unsigned int *fe_index)
571 : {
572 109 : struct vr_flow_entry *fe = NULL;
573 :
574 109 : fe = vr_flow_table_get_free_entry(router, key, fe_index);
575 109 : if (fe) {
576 109 : if (need_hold) {
577 5 : fe->fe_hold_list = vr_zalloc(sizeof(struct vr_flow_queue),
578 : VR_FLOW_QUEUE_OBJECT);
579 5 : if (!fe->fe_hold_list) {
580 0 : vr_flow_reset_entry(router, fe);
581 0 : fe = NULL;
582 0 : vr_printf("%s:%d flow reset\n", __func__, __LINE__);
583 0 : return fe;
584 : } else {
585 5 : fe->fe_hold_list->vfq_index = *fe_index;
586 : }
587 : }
588 :
589 109 : fe->fe_type = type;
590 109 : memcpy(&fe->fe_key, key, key->flow_key_len);
591 109 : fe->fe_key.flow_key_len = key->flow_key_len;
592 : }
593 :
594 109 : return fe;
595 : }
596 :
597 :
598 : struct vr_flow_entry *
599 176 : vr_find_flow(struct vrouter *router, struct vr_flow *key,
600 : uint8_t type, unsigned int *fe_index)
601 : {
602 : struct vr_flow_entry *fe;
603 :
604 176 : fe = (struct vr_flow_entry *)vr_htable_find_hentry(router->vr_flow_table,
605 176 : key, key->flow_key_len);
606 176 : if (fe) {
607 62 : if (fe_index)
608 62 : *fe_index = fe->fe_hentry.hentry_index;
609 : }
610 :
611 176 : return fe;
612 : }
613 :
614 :
615 : void
616 28 : vr_flow_fill_pnode(struct vr_packet_node *pnode, struct vr_packet *pkt,
617 : struct vr_forwarding_md *fmd)
618 : {
619 28 : struct vr_ip *ip = (struct vr_ip *)pkt_inner_network_header(pkt);
620 :
621 : /*
622 : * we cannot cache nexthop here. to cache, we need to hold reference
623 : * to the nexthop. to hold a reference, we will have to hold a lock,
624 : * which we cannot. the only known case of misbehavior if we do not
625 : * cache is ECMP. when the packet comes from the fabric, the nexthop
626 : * actually points to a local composite, whereas a route lookup actually
627 : * returns a different nexthop, in which case the ecmp index will return
628 : * a bad nexthop. to avoid that, we will cache the label, and reuse it
629 : */
630 28 : pkt->vp_nh = NULL;
631 :
632 28 : pnode->pl_flags = 0;
633 28 : pnode->pl_vif_idx = pkt->vp_if->vif_idx;
634 :
635 28 : if (fmd) {
636 28 : pnode->pl_outer_src_ip = fmd->fmd_outer_src_ip;
637 28 : pnode->pl_label = fmd->fmd_label;
638 28 : if (vr_fmd_label_is_vxlan_id(fmd))
639 0 : pnode->pl_flags |= PN_FLAG_LABEL_IS_VXLAN_ID;
640 28 : if (fmd->fmd_to_me)
641 0 : pnode->pl_flags |= PN_FLAG_TO_ME;
642 : }
643 :
644 28 : if (ip) {
645 28 : if (vr_ip_is_ip4(ip)) {
646 : /*
647 : * Source IP & Dest IP can change while the packet is in the queue
648 : * (NAT). For e.g.: when the cloned head of a fragment is enqueued
649 : * to the assembler and subsequently dequeued by the assembler, the
650 : * original packet might have undergone a NAT, resulting in wrong
651 : * hash and thus a wrong search for other fragments of the packet.
652 : * Hence, store them here for others interested in the original IPs
653 : */
654 28 : pnode->pl_inner_src_ip = ip->ip_saddr;
655 28 : pnode->pl_inner_dst_ip = ip->ip_daddr;
656 28 : if (vr_ip_fragment_head(ip))
657 5 : pnode->pl_flags |= PN_FLAG_FRAGMENT_HEAD;
658 0 : } else if (vr_ip_is_ip6(ip)) {
659 0 : if (vr_ip6_fragment_head((struct vr_ip6 *)ip))
660 0 : pnode->pl_flags |= PN_FLAG_FRAGMENT_HEAD;
661 : }
662 : }
663 :
664 28 : pnode->pl_dscp = fmd->fmd_dscp;
665 28 : pnode->pl_dotonep = fmd->fmd_dotonep;
666 28 : pnode->pl_vrf = fmd->fmd_dvrf;
667 28 : pnode->pl_vlan = fmd->fmd_vlan;
668 28 : pnode->pl_mirror_vlan = fmd->fmd_mirror_data;
669 :
670 28 : vr_sync_synchronize();
671 28 : pnode->pl_packet = pkt;
672 :
673 28 : return;
674 : }
675 :
676 : static int
677 7 : vr_enqueue_flow(struct vrouter *router, struct vr_flow_entry *fe,
678 : struct vr_packet *pkt, unsigned int index,
679 : struct vr_flow_stats *stats, struct vr_forwarding_md *fmd)
680 : {
681 7 : int ret = 0;
682 : unsigned int i;
683 7 : unsigned short drop_reason = 0;
684 7 : struct vr_flow_queue *vfq = fe->fe_hold_list;
685 : struct vr_packet_node *pnode;
686 :
687 7 : if (!vfq) {
688 0 : drop_reason = VP_DROP_FLOW_UNUSABLE;
689 0 : PKT_LOG(drop_reason, pkt, 0, VR_FLOW_C, __LINE__);
690 0 : goto drop;
691 : }
692 :
693 7 : i = vr_sync_fetch_and_add_32u(&vfq->vfq_entries, 1);
694 7 : if (i >= VR_MAX_FLOW_QUEUE_ENTRIES) {
695 0 : drop_reason = VP_DROP_FLOW_QUEUE_LIMIT_EXCEEDED;
696 0 : PKT_LOG(drop_reason, pkt, 0, VR_FLOW_C, __LINE__);
697 0 : goto drop;
698 : }
699 :
700 7 : pnode = &vfq->vfq_pnodes[i];
701 7 : vr_flow_fill_pnode(pnode, pkt, fmd);
702 7 : if (!i)
703 5 : ret = vr_trap_flow(router, fe, pkt, index, stats, pnode);
704 :
705 7 : return ret;
706 0 : drop:
707 0 : vr_pfree(pkt, drop_reason);
708 0 : return 0;
709 : }
710 :
711 : static flow_result_t
712 6 : vr_flow_nat(struct vr_flow_entry *fe,
713 : struct vr_packet *pkt, struct vr_forwarding_md *fmd)
714 : {
715 6 : if (pkt->vp_type == VP_TYPE_IP)
716 4 : return vr_inet_flow_nat(fe, pkt, fmd);
717 :
718 2 : if (pkt->vp_type == VP_TYPE_IP6)
719 2 : return vr_inet6_flow_nat(fe, pkt, fmd);
720 :
721 0 : PKT_LOG(VP_DROP_FLOW_ACTION_INVALID, pkt, 0, VR_FLOW_C, __LINE__);
722 0 : vr_pfree(pkt, VP_DROP_FLOW_ACTION_INVALID);
723 0 : return FLOW_CONSUMED;
724 : }
725 :
726 : static void
727 395 : vr_flow_set_forwarding_md(struct vrouter *router, struct vr_flow_entry *fe,
728 : unsigned int index, struct vr_forwarding_md *md)
729 : {
730 : struct vr_flow_entry *rfe;
731 :
732 395 : md->fmd_flow_index = index;
733 395 : md->fmd_ecmp_nh_index = fe->fe_ecmp_nh_index;
734 395 : md->fmd_underlay_ecmp_index = fe->fe_underlay_ecmp_index;
735 395 : md->fmd_udp_src_port = fe->fe_udp_src_port;
736 395 : if (fe->fe_flags & VR_RFLOW_VALID) {
737 320 : rfe = vr_flow_get_entry(router, fe->fe_rflow);
738 320 : if (rfe)
739 275 : md->fmd_ecmp_src_nh_index = rfe->fe_ecmp_nh_index;
740 : }
741 :
742 395 : return;
743 : }
744 :
745 : static bool
746 8 : __vr_flow_mark_evict(struct vrouter *router, struct vr_flow_entry *fe)
747 : {
748 : unsigned short flags;
749 :
750 8 : flags = fe->fe_flags;
751 8 : if (flags & VR_FLOW_FLAG_ACTIVE) {
752 8 : flags = vr_sync_fetch_and_or_16u(&fe->fe_flags,
753 : VR_FLOW_FLAG_EVICT_CANDIDATE);
754 8 : if (!(flags & VR_FLOW_FLAG_EVICT_CANDIDATE)) {
755 8 : return true;
756 : }
757 : }
758 :
759 0 : return false;
760 : }
761 :
762 : static void
763 8 : vr_flow_mark_evict(struct vrouter *router, struct vr_flow_entry *fe,
764 : unsigned int index)
765 : {
766 8 : bool evict_forward_flow = true;
767 :
768 8 : struct vr_flow_entry *rfe = NULL;
769 :
770 : /* start modifying the entry */
771 8 : if (!vr_flow_start_modify(router, fe)) {
772 4 : return;
773 : }
774 :
775 4 : if (fe->fe_rflow >= 0) {
776 4 : rfe = vr_flow_get_entry(router, fe->fe_rflow);
777 4 : if (rfe) {
778 4 : evict_forward_flow = false;
779 4 : if (rfe->fe_tcp_flags & VR_FLOW_TCP_DEAD) {
780 4 : if (!vr_flow_start_modify(router, rfe)) {
781 : /* no modification. hence...*/
782 0 : rfe = NULL;
783 : } else {
784 : /* we do not want hold flows to be evicted, just yet */
785 4 : if (((rfe->fe_rflow == index) || (rfe->fe_rflow < 0)) &&
786 4 : (rfe->fe_action != VR_FLOW_ACTION_HOLD)) {
787 4 : evict_forward_flow = __vr_flow_mark_evict(router, rfe);
788 : }
789 : }
790 : } else {
791 : /* no modification. hence...*/
792 0 : rfe = NULL;
793 : }
794 : }
795 : }
796 :
797 : /*
798 : * presence of rfe means that we might need to reset the evict bit
799 : * or at the minimum reset the modified bit under failure conditions
800 : *
801 : * CEM-18166: In case rfe has already been deleted, under special
802 : * circumstances, fe might still have fe_rflow pointing to it.
803 : * In this case (and other cases where rfe is not active anymore),
804 : * evict_forward_flow will remain true, which makes sense because we still
805 : * want to evict this flow, because of TCP FIN or RST.
806 : */
807 4 : if (evict_forward_flow) {
808 4 : if (__vr_flow_mark_evict(router, fe)) {
809 4 : if (!__vr_flow_schedule_transition(router, fe,
810 4 : index, fe->fe_flags)) {
811 4 : return;
812 : } else {
813 0 : goto reset_evict;
814 : }
815 : }
816 : }
817 :
818 : /* stop modifying the forward and the reverse */
819 0 : if (rfe)
820 0 : vr_flow_stop_modify(router, rfe);
821 0 : vr_flow_stop_modify(router, fe);
822 :
823 0 : return;
824 :
825 0 : reset_evict:
826 0 : if (rfe)
827 0 : vr_flow_reset_evict(router, rfe);
828 0 : vr_flow_reset_evict(router, fe);
829 :
830 0 : return;
831 : }
832 :
833 : int16_t
834 21 : vr_flow_get_qos(struct vrouter *router, struct vr_packet *pkt,
835 : struct vr_forwarding_md *fmd)
836 : {
837 : struct vr_flow_entry *fe;
838 :
839 21 : if (fmd->fmd_flow_index >= 0) {
840 21 : fe = vr_flow_get_entry(router, fmd->fmd_flow_index);
841 21 : if (fe)
842 21 : return fe->fe_qos_id;
843 : }
844 :
845 0 : return -1;
846 : }
847 :
848 : static int
849 0 : vr_rflow_update_ecmp_index(struct vrouter *router, struct vr_flow_entry *fe,
850 : unsigned int new_ecmp_index, struct vr_forwarding_md *fmd)
851 : {
852 : struct vr_flow_entry *rfe;
853 :
854 0 : if (new_ecmp_index == -1)
855 0 : return -1;
856 :
857 0 : rfe = vr_flow_get_entry(router, fe->fe_rflow);
858 0 : if ((!rfe) || (rfe->fe_flags & VR_FLOW_FLAG_DELETE_MARKED))
859 0 : return -1;
860 :
861 0 : rfe->fe_ecmp_nh_index = new_ecmp_index;
862 :
863 : /* Update hardware reverse flow. */
864 0 : (void)vr_offload_flow_set(rfe, fe->fe_rflow, NULL);
865 :
866 0 : fmd->fmd_ecmp_src_nh_index = new_ecmp_index;
867 :
868 0 : return 0;
869 : }
870 :
871 :
872 : int
873 1 : vr_flow_update_ecmp_index(struct vrouter *router, struct vr_flow_entry *fe,
874 : unsigned int new_ecmp_index, struct vr_forwarding_md *fmd)
875 : {
876 :
877 1 : if (new_ecmp_index == -1)
878 0 : return -1;
879 :
880 1 : if ((!fe) || (fe->fe_flags & VR_FLOW_FLAG_DELETE_MARKED))
881 0 : return -1;
882 :
883 : /* If RPF verification is manipulating this flow, let it succeed */
884 1 : (void)vr_sync_bool_compare_and_swap_8s(&fe->fe_ecmp_nh_index,
885 : fmd->fmd_ecmp_nh_index, new_ecmp_index);
886 :
887 1 : fmd->fmd_ecmp_nh_index = fe->fe_ecmp_nh_index;
888 :
889 1 : return 0;
890 : }
891 :
892 : static flow_result_t
893 61 : vr_flow_action_default(struct vrouter *router, struct vr_flow_entry *fe,
894 : unsigned int index, struct vr_packet *pkt,
895 : struct vr_forwarding_md *fmd)
896 : {
897 61 : unsigned int ip_inc_diff_cksum = 0;
898 : struct vr_ip *ip;
899 61 : flow_result_t result = FLOW_CONSUMED;
900 :
901 : struct vr_forwarding_md mirror_fmd;
902 :
903 61 : fmd->fmd_dvrf = fe->fe_vrf;
904 : /*
905 : * for now, we will not use dvrf if VRFT is set, because the RPF
906 : * check needs to happen in the source vrf
907 : */
908 :
909 61 : if (fe->fe_flags & VR_FLOW_FLAG_VRFT) {
910 5 : if (fmd->fmd_dvrf != fe->fe_dvrf) {
911 1 : fmd->fmd_dvrf = fe->fe_dvrf;
912 1 : fmd->fmd_to_me = 1;
913 : }
914 : }
915 :
916 61 : if (fe->fe_flags & VR_FLOW_FLAG_MIRROR) {
917 2 : if (fe->fe_mirror_id < VR_MAX_MIRROR_INDICES) {
918 2 : mirror_fmd = *fmd;
919 2 : mirror_fmd.fmd_ecmp_nh_index = -1;
920 2 : mirror_fmd.fmd_underlay_ecmp_index = -1;
921 2 : vr_mirror(router, fe->fe_mirror_id, pkt, &mirror_fmd,
922 : MIRROR_TYPE_ACL);
923 2 : fmd->fmd_mirror_data = mirror_fmd.fmd_mirror_data;
924 : }
925 :
926 2 : if (fe->fe_sec_mirror_id < VR_MAX_MIRROR_INDICES) {
927 0 : mirror_fmd = *fmd;
928 0 : mirror_fmd.fmd_ecmp_nh_index = -1;
929 0 : mirror_fmd.fmd_underlay_ecmp_index = -1;
930 0 : vr_mirror(router, fe->fe_sec_mirror_id, pkt, &mirror_fmd,
931 : MIRROR_TYPE_ACL);
932 0 : fmd->fmd_mirror_data = mirror_fmd.fmd_mirror_data;
933 : }
934 : }
935 :
936 61 : switch (fe->fe_action) {
937 0 : case VR_FLOW_ACTION_DROP:
938 0 : PKT_LOG(VP_DROP_FLOW_ACTION_DROP, pkt, 0, VR_FLOW_C, __LINE__);
939 0 : vr_pfree(pkt, VP_DROP_FLOW_ACTION_DROP);
940 0 : result = FLOW_CONSUMED;
941 0 : break;
942 :
943 55 : case VR_FLOW_ACTION_FORWARD:
944 55 : result = FLOW_FORWARD;
945 55 : break;
946 :
947 6 : case VR_FLOW_ACTION_NAT:
948 6 : result = vr_flow_nat(fe, pkt, fmd);
949 6 : break;
950 :
951 0 : default:
952 0 : PKT_LOG(VP_DROP_FLOW_ACTION_INVALID, pkt, 0, VR_FLOW_C, __LINE__);
953 0 : vr_pfree(pkt, VP_DROP_FLOW_ACTION_INVALID);
954 0 : result = FLOW_CONSUMED;
955 0 : break;
956 : }
957 :
958 61 : if (result == FLOW_FORWARD) {
959 61 : if (pkt->vp_type == VP_TYPE_IP) {
960 57 : ip = (struct vr_ip *)pkt_network_header(pkt);
961 57 : if (ip) {
962 57 : if (fe->fe_ttl && (fe->fe_ttl != ip->ip_ttl)) {
963 0 : vr_incremental_diff(ip->ip_ttl, fe->fe_ttl, &ip_inc_diff_cksum);
964 0 : ip->ip_ttl = fe->fe_ttl;
965 :
966 0 : if (ip_inc_diff_cksum)
967 0 : vr_ip_incremental_csum(ip, ip_inc_diff_cksum);
968 : }
969 : }
970 : }
971 : }
972 :
973 61 : if (fe->fe_tcp_flags & VR_FLOW_TCP_DEAD)
974 4 : vr_flow_mark_evict(router, fe, index);
975 :
976 61 : return result;
977 : }
978 :
979 : static flow_result_t
980 62 : vr_flow_action_hbs(struct vrouter *router, struct vr_flow_entry *fe,
981 : unsigned int index, struct vr_packet *pkt,
982 : struct vr_forwarding_md *fmd)
983 : {
984 62 : struct vr_vrf_table_entry *vrf_entry = NULL;
985 : uint16_t dvrf;
986 :
987 62 : dvrf = (fmd->fmd_dvrf == -1)? fe->fe_vrf: fmd->fmd_dvrf;
988 :
989 : /* If not HBS flow, return */
990 62 : if (!(fe->fe_flags1 & VR_FLOW_FLAG1_HBS_MASK))
991 53 : return FLOW_FORWARD;
992 :
993 9 : vrf_entry = vrouter_get_vrf_table(router, dvrf);
994 :
995 : /* Packet entering vrouter and going to hbs-l or hbs-r
996 : * for hbs-flows
997 : */
998 9 : if (fe->fe_flags1 & VR_FLOW_FLAG1_HBS_LEFT) {
999 : struct vr_interface *hbs_l;
1000 :
1001 : /* Flow is marked as HBS, but there is no HBS instance,
1002 : * so drop the packet
1003 : */
1004 4 : if (!vrf_entry) {
1005 0 : PKT_LOG(VP_DROP_INVALID_HBS_PKT, pkt, 0, VR_FLOW_C, __LINE__);
1006 0 : goto drop_pkt;
1007 : }
1008 :
1009 4 : hbs_l = vrf_entry->hbs_l_vif;
1010 4 : if (hbs_l) {
1011 : struct vr_eth_hbs_md *eth_hbs;
1012 :
1013 4 : if (vif_is_virtual(pkt->vp_if)) {
1014 : /* Packet entering vrouter from vmi and going to hbs-l,
1015 : * encode flow_id in src mac
1016 : */
1017 4 : eth_hbs = (struct vr_eth_hbs_md*)pkt_data(pkt);
1018 4 : eth_hbs->flow_id_smac = htonl(index);
1019 4 : eth_hbs->magic_smac = htons(VR_HBS_SMAC_MAGIC | VR_HBS_FROM_VMI);
1020 0 : } else if (vif_is_fabric(pkt->vp_if)) {
1021 : /* Packet entering vrouter from fabric and going to hbs-l
1022 : * (service chaining case) encode flow_id in dst mac
1023 : */
1024 :
1025 : /* Add ethernet header if there is none */
1026 0 : if (pkt_data(pkt) == pkt_network_header(pkt)) {
1027 0 : struct vr_eth *eth = (struct vr_eth*)pkt_data(pkt);
1028 0 : eth = (struct vr_eth *)pkt_push(pkt, VR_ETHER_HLEN);
1029 0 : memcpy(eth->eth_dmac, hbs_l->vif_mac, VR_ETHER_ALEN);
1030 0 : memcpy(eth->eth_smac, hbs_l->vif_mac, VR_ETHER_ALEN);
1031 0 : if (pkt->vp_type == VP_TYPE_IP) {
1032 0 : eth->eth_proto = htons(VR_ETH_PROTO_IP);
1033 0 : } else if (pkt->vp_type == VP_TYPE_IP6) {
1034 0 : eth->eth_proto = htons(VR_ETH_PROTO_IP6);
1035 : }
1036 : }
1037 :
1038 0 : eth_hbs = (struct vr_eth_hbs_md*)pkt_data(pkt);
1039 0 : eth_hbs->flow_id_dmac = htonl(index);
1040 0 : eth_hbs->magic_dmac = htons(VR_HBS_DMAC_MAGIC | VR_HBS_FROM_FABRIC);
1041 : }
1042 4 : pkt->vp_if = hbs_l;
1043 : /*
1044 : * If for some reason, we have GRO flag set and we have not invoked
1045 : * the GRO, we need to unset
1046 : */
1047 4 : vr_pkt_unset_gro(pkt);
1048 4 : pkt->vp_nh = NULL;
1049 4 : hbs_l->vif_tx(hbs_l, pkt, fmd);
1050 4 : return FLOW_HELD;
1051 : }
1052 0 : return FLOW_FORWARD;
1053 5 : } else if (fe->fe_flags1 & VR_FLOW_FLAG1_HBS_RIGHT) {
1054 : struct vr_interface *hbs_r;
1055 :
1056 : /* Flow is marked as HBS, but there is no HBS instance,
1057 : * so drop the packet
1058 : */
1059 5 : if (!vrf_entry) {
1060 0 : PKT_LOG(VP_DROP_INVALID_HBS_PKT, pkt, 0, VR_FLOW_C, __LINE__);
1061 0 : goto drop_pkt;
1062 : }
1063 :
1064 5 : hbs_r = vrf_entry->hbs_r_vif;
1065 5 : if (hbs_r) {
1066 : /* Packet entering vrouter from fabric and going to hbs-r,
1067 : * encode flow_id in dst mac
1068 : *
1069 : * Note: packet can also enter vrouter and goto hbs-r
1070 : * from vmi (instead of fabric) in case of intra-compute
1071 : */
1072 : struct vr_eth *eth;
1073 : struct vr_eth_hbs_md *eth_hbs;
1074 5 : bool pkt_is_l3 = false;
1075 :
1076 : /* Add ethernet header if there is none */
1077 5 : if (pkt_data(pkt) == pkt_network_header(pkt)) {
1078 1 : eth = (struct vr_eth *)pkt_push(pkt, VR_ETHER_HLEN);
1079 1 : memcpy(eth->eth_dmac, hbs_r->vif_mac, VR_ETHER_ALEN);
1080 1 : memcpy(eth->eth_smac, hbs_r->vif_mac, VR_ETHER_ALEN);
1081 1 : if (pkt->vp_type == VP_TYPE_IP) {
1082 1 : eth->eth_proto = htons(VR_ETH_PROTO_IP);
1083 0 : } else if (pkt->vp_type == VP_TYPE_IP6) {
1084 0 : eth->eth_proto = htons(VR_ETH_PROTO_IP6);
1085 : }
1086 1 : pkt_is_l3 = true;
1087 : }
1088 :
1089 5 : eth_hbs = (struct vr_eth_hbs_md*)pkt_data(pkt);
1090 :
1091 5 : eth = (struct vr_eth*)pkt_data(pkt);
1092 5 : if (!pkt_is_l3 && !memcmp(eth->eth_dmac, hbs_r->vif_mac, VR_ETHER_ALEN))
1093 1 : pkt_is_l3 = true;
1094 :
1095 5 : eth_hbs->flow_id_dmac = htonl(index);
1096 :
1097 : /* Encode packet source in the header */
1098 5 : if (vif_is_virtual(pkt->vp_if))
1099 2 : eth_hbs->magic_dmac = htons(VR_HBS_DMAC_MAGIC | VR_HBS_FROM_VMI);
1100 3 : else if (vif_is_fabric(pkt->vp_if))
1101 3 : eth_hbs->magic_dmac = htons(VR_HBS_DMAC_MAGIC | VR_HBS_FROM_FABRIC);
1102 : /* If it's L3 packet, encode it */
1103 5 : if (pkt_is_l3)
1104 2 : eth_hbs->magic_dmac |= htons(VR_HBS_L3_PKT);
1105 :
1106 5 : pkt->vp_if = hbs_r;
1107 : /*
1108 : * If for some reason, we have GRO flag set and we have not invoked
1109 : * the GRO, we need to unset
1110 : */
1111 5 : vr_pkt_unset_gro(pkt);
1112 5 : pkt->vp_nh = NULL;
1113 5 : hbs_r->vif_tx(hbs_r, pkt, fmd);
1114 5 : return FLOW_HELD;
1115 : }
1116 0 : return FLOW_FORWARD;
1117 : }
1118 0 : return FLOW_FORWARD;
1119 :
1120 0 : drop_pkt:
1121 0 : vr_pfree(pkt, VP_DROP_INVALID_HBS_PKT);
1122 0 : return FLOW_HELD;
1123 : }
1124 :
1125 : static flow_result_t
1126 62 : vr_flow_action(struct vrouter *router, struct vr_flow_entry *fe,
1127 : unsigned int index, struct vr_packet *pkt,
1128 : struct vr_forwarding_md *fmd)
1129 : {
1130 62 : flow_result_t ret = FLOW_CONSUMED;
1131 : struct vr_nexthop *src_nh;
1132 62 : int valid_src, modified_index = -1;
1133 :
1134 62 : src_nh = __vrouter_get_nexthop(router, fe->fe_src_nh_index);
1135 62 : if (!src_nh) {
1136 0 : PKT_LOG(VP_DROP_INVALID_NH, pkt, 0, VR_FLOW_C, __LINE__);
1137 0 : vr_pfree(pkt, VP_DROP_INVALID_NH);
1138 0 : goto res;
1139 : }
1140 :
1141 62 : if (src_nh->nh_validate_src) {
1142 60 : valid_src = src_nh->nh_validate_src(pkt, src_nh, fmd, &modified_index);
1143 60 : if (valid_src == NH_SOURCE_INVALID) {
1144 0 : PKT_LOG(VP_DROP_INVALID_SOURCE, pkt, 0, VR_FLOW_C, __LINE__);
1145 0 : vr_pfree(pkt, VP_DROP_INVALID_SOURCE);
1146 0 : goto res;
1147 : }
1148 :
1149 60 : if (valid_src == NH_SOURCE_MISMATCH) {
1150 0 : valid_src = vr_rflow_update_ecmp_index(router, fe,
1151 : modified_index, fmd);
1152 0 : if (valid_src == -1) {
1153 0 : PKT_LOG(VP_DROP_INVALID_SOURCE, pkt, 0, VR_FLOW_C, __LINE__);
1154 0 : vr_pfree(pkt, VP_DROP_INVALID_SOURCE);
1155 0 : goto res;
1156 : }
1157 : }
1158 : }
1159 :
1160 :
1161 124 : if ((fe->fe_action == VR_FLOW_ACTION_DROP) ||
1162 62 : ((ret = vr_flow_action_hbs(router, fe, index, pkt, fmd)) != FLOW_HELD))
1163 53 : ret = vr_flow_action_default(router, fe, index, pkt, fmd);
1164 :
1165 9 : res:
1166 62 : if (fe->fe_tcp_flags & VR_FLOW_TCP_DEAD)
1167 4 : vr_flow_mark_evict(router, fe, index);
1168 :
1169 62 : return ret;
1170 : }
1171 :
1172 : unsigned int
1173 5 : vr_trap_flow(struct vrouter *router, struct vr_flow_entry *fe,
1174 : struct vr_packet *pkt, unsigned int index,
1175 : struct vr_flow_stats *stats, struct vr_packet_node *pnode)
1176 : {
1177 : unsigned int trap_reason;
1178 :
1179 : struct vr_packet *npkt;
1180 : struct vr_flow_trap_arg ta;
1181 :
1182 5 : npkt = vr_pclone(pkt);
1183 5 : if (!npkt) {
1184 : /* Lets manipulate the stats */
1185 0 : pkt_drop_stats(pkt->vp_if, VP_DROP_TRAP_ORIGINAL, pkt->vp_cpu);
1186 0 : if (pnode)
1187 0 : pnode->pl_packet = NULL;
1188 0 : npkt = pkt;
1189 : }
1190 :
1191 5 : vr_preset(npkt);
1192 :
1193 5 : switch (fe->fe_flags & VR_FLOW_FLAG_TRAP_MASK) {
1194 : default:
1195 : /*
1196 : * agent needs a method to identify new flows from existing flows.
1197 : * existing flows can be reused (evicted) or the action of such flows
1198 : * can become hold. If existing flows are reused and packet is trapped,
1199 : * agent will not re-evaluate the flow. Hence, agent has to be told
1200 : * that this is a new flow, which we indicate by the trap reason.
1201 : */
1202 5 : if (fe->fe_flags & VR_FLOW_FLAG_NEW_FLOW) {
1203 5 : trap_reason = AGENT_TRAP_FLOW_MISS;
1204 5 : fe->fe_flags ^= VR_FLOW_FLAG_NEW_FLOW;
1205 : } else {
1206 0 : trap_reason = AGENT_TRAP_FLOW_ACTION_HOLD;
1207 : }
1208 :
1209 5 : ta.vfta_index = index;
1210 5 : if ((fe->fe_type == VP_TYPE_IP) || (fe->fe_type == VP_TYPE_IP6))
1211 5 : ta.vfta_nh_index = fe->fe_key.flow_nh_id;
1212 5 : if (stats) {
1213 5 : ta.vfta_stats = *stats;
1214 : } else {
1215 0 : ta.vfta_stats = fe->fe_stats;
1216 : }
1217 :
1218 5 : ta.vfta_gen_id = fe->fe_gen_id;
1219 :
1220 5 : break;
1221 : }
1222 :
1223 5 : return vr_trap(npkt, fe->fe_vrf, trap_reason, &ta);
1224 : }
1225 :
1226 : static flow_result_t
1227 67 : vr_do_flow_action(struct vrouter *router, struct vr_flow_entry *fe,
1228 : unsigned int index, struct vr_packet *pkt,
1229 : struct vr_forwarding_md *fmd)
1230 : {
1231 : uint32_t new_stats;
1232 67 : struct vr_flow_stats stats, *stats_p = NULL;
1233 :
1234 67 : if (fe->fe_flags & VR_FLOW_FLAG_NEW_FLOW) {
1235 5 : memcpy(&stats, &fe->fe_stats, sizeof(fe->fe_stats));
1236 5 : memset(&fe->fe_stats, 0, sizeof(fe->fe_stats));
1237 5 : stats_p = &stats;
1238 : }
1239 :
1240 67 : new_stats = vr_sync_add_and_fetch_32u(&fe->fe_stats.flow_bytes, pkt_len(pkt));
1241 67 : if (new_stats < pkt_len(pkt))
1242 0 : fe->fe_stats.flow_bytes_oflow++;
1243 :
1244 67 : new_stats = vr_sync_add_and_fetch_32u(&fe->fe_stats.flow_packets, 1);
1245 67 : if (!new_stats)
1246 0 : fe->fe_stats.flow_packets_oflow++;
1247 :
1248 67 : if (fe->fe_action == VR_FLOW_ACTION_HOLD) {
1249 7 : vr_enqueue_flow(router, fe, pkt, index, stats_p, fmd);
1250 7 : return FLOW_HELD;
1251 : }
1252 :
1253 60 : return vr_flow_action(router, fe, index, pkt, fmd);
1254 : }
1255 :
1256 : static unsigned int
1257 18 : vr_flow_table_hold_count(struct vrouter *router)
1258 : {
1259 : unsigned int i, num_cpus;
1260 18 : uint64_t hcount = 0, act_count;
1261 18 : struct vr_flow_table_info *infop = router->vr_flow_table_info;
1262 :
1263 18 : num_cpus = vr_num_cpus;
1264 234 : for (i = 0; i < num_cpus; i++)
1265 216 : hcount += infop->vfti_hold_count[i];
1266 :
1267 18 : act_count = infop->vfti_action_count;
1268 18 : if (hcount >= act_count)
1269 18 : return hcount - act_count;
1270 :
1271 0 : return 0;
1272 : }
1273 :
1274 : static void
1275 0 : vr_flow_burst_timeout(void *arg)
1276 : {
1277 : int tokens;
1278 0 : struct vrouter *router = (struct vrouter *)arg;
1279 0 : struct vr_flow_table_info *infop = router->vr_flow_table_info;
1280 :
1281 0 : tokens = infop->vfti_burst_tokens - infop->vfti_burst_used;
1282 0 : if (tokens > 0) {
1283 :
1284 0 : tokens = infop->vfti_burst_tokens_configured - tokens;
1285 0 : if (tokens <= 0) {
1286 0 : infop->vfti_timer->vt_stop_timer = 1;
1287 0 : return;
1288 : }
1289 :
1290 0 : if (tokens > infop->vfti_burst_step_configured)
1291 0 : tokens = infop->vfti_burst_step_configured;
1292 : } else {
1293 0 : tokens = infop->vfti_burst_step_configured;
1294 : }
1295 :
1296 0 : infop->vfti_burst_tokens += tokens;
1297 :
1298 0 : return;
1299 : }
1300 :
1301 : static void
1302 0 : vr_flow_start_burst_processing(struct vrouter *router)
1303 : {
1304 : struct vr_timer *vtimer;
1305 0 : struct vr_flow_table_info *infop = router->vr_flow_table_info;
1306 :
1307 0 : if (!infop->vfti_burst_tokens_configured ||
1308 0 : !infop->vfti_burst_interval_configured ||
1309 0 : !infop->vfti_burst_step_configured) {
1310 0 : return;
1311 : }
1312 :
1313 0 : if (!infop->vfti_timer) {
1314 0 : vtimer = vr_zalloc(sizeof(*vtimer), VR_TIMER_OBJECT);
1315 0 : if (!vtimer) {
1316 0 : vr_module_error(-ENOMEM, __FUNCTION__, __LINE__, sizeof(*vtimer));
1317 0 : return;
1318 : }
1319 :
1320 0 : vtimer->vt_timer = vr_flow_burst_timeout;
1321 0 : vtimer->vt_vr_arg = router;
1322 0 : vtimer->vt_msecs = infop->vfti_burst_interval_configured;
1323 :
1324 0 : if (vr_create_timer(vtimer)) {
1325 0 : vr_free(vtimer, VR_TIMER_OBJECT);
1326 0 : return;
1327 : }
1328 :
1329 0 : infop->vfti_timer = vtimer;
1330 : } else {
1331 0 : if (!infop->vfti_timer->vt_stop_timer)
1332 0 : return;
1333 :
1334 0 : if (vr_sync_bool_compare_and_swap_32u(
1335 : &infop->vfti_timer->vt_stop_timer, 1, 0)) {
1336 0 : infop->vfti_timer->vt_msecs = infop->vfti_burst_interval_configured;
1337 0 : vr_restart_timer(infop->vfti_timer);
1338 : }
1339 : }
1340 :
1341 0 : return;
1342 : }
1343 :
1344 : static void
1345 5 : vr_flow_entry_set_hold(struct vrouter *router, struct vr_flow_entry
1346 : *flow_e, bool burst)
1347 : {
1348 : unsigned int cpu;
1349 : uint64_t act_count;
1350 5 : struct vr_flow_table_info *infop = router->vr_flow_table_info;
1351 :
1352 5 : cpu = vr_get_cpu();
1353 5 : if (cpu >= vr_num_cpus) {
1354 0 : vr_printf("vrouter: Set HOLD failed (cpu %u num_cpus %u)\n",
1355 : cpu, vr_num_cpus);
1356 0 : return;
1357 : }
1358 :
1359 5 : flow_e->fe_action = VR_FLOW_ACTION_HOLD;
1360 :
1361 5 : if (infop->vfti_hold_count[cpu] + 1 < infop->vfti_hold_count[cpu]) {
1362 0 : (void)vr_sync_add_and_fetch_32u(&infop->vfti_oflows, 1);
1363 0 : act_count = infop->vfti_action_count;
1364 0 : if (act_count > infop->vfti_hold_count[cpu]) {
1365 0 : (void)vr_sync_sub_and_fetch_64u(&infop->vfti_action_count,
1366 : infop->vfti_hold_count[cpu]);
1367 0 : infop->vfti_hold_count[cpu] = 0;
1368 : } else {
1369 0 : infop->vfti_hold_count[cpu] -= act_count;
1370 0 : (void)vr_sync_sub_and_fetch_64u(&infop->vfti_action_count,
1371 : act_count);
1372 : }
1373 : }
1374 :
1375 5 : infop->vfti_hold_count[cpu]++;
1376 :
1377 5 : if (burst == true) {
1378 0 : (void)vr_sync_add_and_fetch_64u(&infop->vfti_burst_used, 1);
1379 0 : vr_flow_start_burst_processing(router);
1380 : }
1381 :
1382 5 : return;
1383 : }
1384 :
1385 : static void
1386 4 : vr_flow_init_close(struct vrouter *router, struct vr_flow_entry *flow_e,
1387 : struct vr_packet *pkt, struct vr_forwarding_md *fmd)
1388 : {
1389 : struct vr_flow_entry *rfe;
1390 :
1391 4 : (void)vr_sync_fetch_and_or_16u(&flow_e->fe_tcp_flags, VR_FLOW_TCP_DEAD);
1392 4 : rfe = vr_flow_get_entry(router, flow_e->fe_rflow);
1393 4 : if (rfe) {
1394 4 : (void)vr_sync_fetch_and_or_16u(&rfe->fe_tcp_flags, VR_FLOW_TCP_DEAD);
1395 : }
1396 :
1397 4 : return;
1398 : }
1399 :
1400 : static void
1401 49 : vr_flow_tcp_rflow_set(struct vrouter *router, struct vr_flow_entry *fe,
1402 : struct vr_flow_entry *rfe)
1403 : {
1404 49 : uint16_t flags = 0;
1405 :
1406 49 : if (!fe || !rfe)
1407 0 : return;
1408 :
1409 49 : if (rfe->fe_tcp_flags & VR_FLOW_TCP_SYN) {
1410 1 : flags |= VR_FLOW_TCP_SYN_R;
1411 : }
1412 :
1413 49 : if (rfe->fe_tcp_flags & VR_FLOW_TCP_RST) {
1414 0 : flags |= VR_FLOW_TCP_RST;
1415 : }
1416 :
1417 49 : if (rfe->fe_tcp_flags & VR_FLOW_TCP_DEAD) {
1418 0 : flags |= VR_FLOW_TCP_DEAD;
1419 : }
1420 :
1421 49 : if (rfe->fe_tcp_flags & VR_FLOW_TCP_FIN) {
1422 0 : flags |= VR_FLOW_TCP_FIN_R;
1423 : }
1424 :
1425 49 : if (rfe->fe_tcp_flags & VR_FLOW_TCP_ESTABLISHED) {
1426 0 : flags |= (VR_FLOW_TCP_ESTABLISHED | VR_FLOW_TCP_ESTABLISHED_R);
1427 : }
1428 :
1429 49 : (void)vr_sync_fetch_and_or_16u(&fe->fe_tcp_flags, flags);
1430 49 : return;
1431 : }
1432 :
1433 : static void
1434 67 : vr_flow_tcp_digest(struct vrouter *router, struct vr_flow_entry *flow_e,
1435 : struct vr_packet *pkt, struct vr_forwarding_md *fmd)
1436 : {
1437 67 : uint8_t proto = 0, hlen = 0;
1438 : uint16_t tcp_offset_flags;
1439 67 : unsigned int length = 0;
1440 : uint16_t flow_tcp_flags;
1441 :
1442 : struct vr_ip *iph;
1443 : struct vr_ip6 *ip6h;
1444 : struct vr_tcp *tcph;
1445 : struct vr_ip6_frag *v6_frag;
1446 67 : struct vr_flow_entry *rflow_e = NULL;
1447 : unsigned int rflow_ack;
1448 :
1449 67 : if (pkt->vp_type == VP_TYPE_IP) {
1450 63 : iph = (struct vr_ip *)pkt_network_header(pkt);
1451 63 : if (!vr_ip_transport_header_valid(iph))
1452 12 : return;
1453 51 : proto = iph->ip_proto;
1454 :
1455 51 : length = ntohs(iph->ip_len) - (iph->ip_hl * 4);
1456 51 : hlen = iph->ip_hl * 4;
1457 4 : } else if (pkt->vp_type == VP_TYPE_IP6) {
1458 4 : ip6h = (struct vr_ip6 *)pkt_network_header(pkt);
1459 4 : if (!vr_ip6_transport_header_valid(ip6h))
1460 0 : return;
1461 4 : proto = ip6h->ip6_nxt;
1462 4 : length = ntohs(ip6h->ip6_plen);
1463 4 : hlen = sizeof(struct vr_ip6);
1464 4 : if (proto == VR_IP6_PROTO_FRAG) {
1465 0 : v6_frag = (struct vr_ip6_frag *)(ip6h + 1);
1466 0 : proto = v6_frag->ip6_frag_nxt;
1467 0 : length -= sizeof(struct vr_ip6_frag);
1468 0 : hlen += sizeof(struct vr_ip6_frag);
1469 : }
1470 : }
1471 :
1472 55 : if (proto != VR_IP_PROTO_TCP)
1473 35 : return;
1474 :
1475 20 : tcph = (struct vr_tcp *)(pkt_network_header(pkt) + hlen);
1476 :
1477 20 : if (tcph) {
1478 20 : if (vr_flow_is_fat_flow(router, pkt, flow_e))
1479 0 : return;
1480 :
1481 : /*
1482 : * there are some optimizations here that makes the code slightly
1483 : * not so frugal. For e.g.: the *_R flags are used to make sure that
1484 : * for a packet that contains ACK, we will not need to fetch the
1485 : * reverse flow if we are not interested, thus saving some execution
1486 : * time.
1487 : */
1488 20 : tcp_offset_flags = ntohs(tcph->tcp_offset_r_flags);
1489 :
1490 : /*
1491 : * If this is an ack, set the last acked seqnum
1492 : */
1493 20 : if (tcp_offset_flags & VR_TCP_FLAG_ACK) {
1494 9 : flow_e->fe_tcp_ack = ntohl(tcph->tcp_ack);
1495 : }
1496 :
1497 : /*
1498 : * if we get a reset, TCP session will be closed if the
1499 : * vr_uncond_close_flow_on_tcp_rst flag is enabled or the TCP RST
1500 : * seqnum matches with the seqnum acked by the receiver
1501 : * - as per RFC 5961 sec 3.2
1502 : */
1503 20 : if (tcp_offset_flags & VR_TCP_FLAG_RST) {
1504 6 : if (!vr_uncond_close_flow_on_tcp_rst) {
1505 : /* get the reverse flow ack seq num if valid */
1506 4 : if (flow_e->fe_flags & VR_RFLOW_VALID) {
1507 4 : rflow_e = vr_flow_get_entry(router, flow_e->fe_rflow);
1508 : }
1509 4 : if (rflow_e) {
1510 4 : rflow_ack = rflow_e->fe_tcp_ack;
1511 : /* Implementing rfc-5961 (section 3.2),
1512 : * In the SYN-SENT state (a RST received in response to an initial SYN),
1513 : * the RST is acceptable if the ACK field acknowledges the SYN. In all
1514 : * other cases the receiver MUST silently discard the segment. */
1515 4 : if ((tcp_offset_flags & VR_TCP_FLAG_ACK)
1516 2 : && (rflow_e->fe_tcp_flags & VR_FLOW_TCP_SYN)) {
1517 2 : if (ntohl(tcph->tcp_ack) != (rflow_e->fe_tcp_seq + 1)) {
1518 : /* Ignore the RST */
1519 1 : return;
1520 : }
1521 : }
1522 2 : else if (ntohl(tcph->tcp_seq) != rflow_ack) {
1523 : /* Ignore the RST */
1524 1 : return;
1525 : }
1526 : }
1527 : /* If Reverse flow not valid, go ahead and close this flow */
1528 : }
1529 :
1530 4 : (void)vr_sync_fetch_and_or_16u(&flow_e->fe_tcp_flags,
1531 : VR_FLOW_TCP_RST);
1532 4 : if (flow_e->fe_flags & VR_RFLOW_VALID) {
1533 4 : rflow_e = vr_flow_get_entry(router, flow_e->fe_rflow);
1534 4 : if (rflow_e) {
1535 4 : (void)vr_sync_fetch_and_or_16u(&rflow_e->fe_tcp_flags,
1536 : VR_FLOW_TCP_RST);
1537 : }
1538 : }
1539 4 : vr_flow_init_close(router, flow_e, pkt, fmd);
1540 4 : return;
1541 14 : } else if (tcp_offset_flags & VR_TCP_FLAG_SYN) {
1542 : /* if only a SYN... */
1543 11 : flow_e->fe_tcp_seq = ntohl(tcph->tcp_seq);
1544 11 : (void)vr_sync_fetch_and_or_16u(&flow_e->fe_tcp_flags, VR_FLOW_TCP_SYN);
1545 11 : if (flow_e->fe_flags & VR_RFLOW_VALID) {
1546 9 : rflow_e = vr_flow_get_entry(router, flow_e->fe_rflow);
1547 9 : if (rflow_e) {
1548 9 : (void)vr_sync_fetch_and_or_16u(&rflow_e->fe_tcp_flags,
1549 : VR_FLOW_TCP_SYN_R);
1550 9 : if ((flow_e->fe_tcp_flags & VR_FLOW_TCP_SYN_R) &&
1551 3 : (tcp_offset_flags & VR_TCP_FLAG_ACK)) {
1552 3 : if (ntohl(tcph->tcp_ack) == (rflow_e->fe_tcp_seq + 1)) {
1553 3 : (void)vr_sync_fetch_and_or_16u(&rflow_e->fe_tcp_flags,
1554 : VR_FLOW_TCP_ESTABLISHED);
1555 3 : flow_tcp_flags = vr_sync_fetch_and_or_16u(
1556 : &flow_e->fe_tcp_flags, VR_FLOW_TCP_ESTABLISHED_R);
1557 3 : if (!(flow_tcp_flags & VR_FLOW_TCP_ESTABLISHED_R) &&
1558 3 : !(flow_tcp_flags & VR_FLOW_TCP_ESTABLISHED)) {
1559 : // If it wasn't established or reverse established,
1560 : // it is being established now. Offload both.
1561 3 : vr_offload_flow_set(flow_e,
1562 : flow_e->fe_hentry.hentry_index, rflow_e);
1563 3 : vr_offload_flow_set(rflow_e,
1564 : rflow_e->fe_hentry.hentry_index, flow_e);
1565 : }
1566 : }
1567 : }
1568 : }
1569 : }
1570 3 : } else if (tcp_offset_flags & VR_TCP_FLAG_FIN) {
1571 : /*
1572 : * when a FIN is received, update the sequence of the FIN and set
1573 : * the flow FIN flag. It is possible that the FIN packet came with
1574 : * some data, in which case the sequence number of the FIN is one
1575 : * more than the last data byte in the sequence
1576 : */
1577 0 : length -= (((tcp_offset_flags) >> 12) * 4);
1578 0 : flow_e->fe_tcp_seq = ntohl(tcph->tcp_seq) + length;
1579 0 : (void)vr_sync_fetch_and_or_16u(&flow_e->fe_tcp_flags, VR_FLOW_TCP_FIN);
1580 : /*
1581 : * when an ack for a FIN is sent, we need to take some actions
1582 : * on the reverse flow (since FIN came in the reverse flow). to
1583 : * avoid looking up the reverse flow for all acks, we mark the
1584 : * reverse flow's reverse flow with a flag (FIN_R). we will
1585 : * lookup the reverse flow only if this flag is set and the
1586 : * tcp header has an ack bit set
1587 : */
1588 0 : if (flow_e->fe_flags & VR_RFLOW_VALID) {
1589 0 : rflow_e = vr_flow_get_entry(router, flow_e->fe_rflow);
1590 : /* Delete offloaded flow on TCP FIN */
1591 0 : (void)vr_offload_flow_del(flow_e);
1592 0 : if (rflow_e) {
1593 0 : (void)vr_sync_fetch_and_or_16u(&rflow_e->fe_tcp_flags,
1594 : VR_FLOW_TCP_FIN_R);
1595 : /* Delete offloaded reverse flow on TCP FIN */
1596 0 : (void)vr_offload_flow_del(rflow_e);
1597 : }
1598 : }
1599 : }
1600 :
1601 : /*
1602 : * if FIN_R is set in the flow and if the ACK bit is set in the
1603 : * tcp header, then we need to mark the reverse flow as dead.
1604 : *
1605 : * OR
1606 : *
1607 : * if the SYN_R is set and ESTABLISHED_R is not set and if this
1608 : * is an ack packet, if this ack completes the connection, we
1609 : * need to set ESTABLISHED
1610 : */
1611 14 : if (((flow_e->fe_tcp_flags & VR_FLOW_TCP_FIN_R) ||
1612 14 : (!(flow_e->fe_tcp_flags & VR_FLOW_TCP_ESTABLISHED_R) &&
1613 11 : (flow_e->fe_tcp_flags & VR_FLOW_TCP_SYN_R))) &&
1614 3 : (tcp_offset_flags & VR_TCP_FLAG_ACK)) {
1615 3 : if (flow_e->fe_flags & VR_RFLOW_VALID) {
1616 3 : if (!rflow_e) {
1617 3 : rflow_e = vr_flow_get_entry(router, flow_e->fe_rflow);
1618 : }
1619 :
1620 3 : if (rflow_e) {
1621 3 : if ((ntohl(tcph->tcp_ack) == (rflow_e->fe_tcp_seq + 1)) &&
1622 3 : (flow_e->fe_tcp_flags & VR_FLOW_TCP_FIN_R)) {
1623 0 : (void)vr_sync_fetch_and_or_16u(&rflow_e->fe_tcp_flags,
1624 : VR_FLOW_TCP_HALF_CLOSE);
1625 : /*
1626 : * both the forward and the reverse flows are
1627 : * now dead
1628 : */
1629 0 : if (flow_e->fe_tcp_flags & VR_FLOW_TCP_HALF_CLOSE) {
1630 0 : vr_flow_init_close(router, flow_e, pkt, fmd);
1631 : }
1632 3 : } else if (ntohl(tcph->tcp_ack) != rflow_e->fe_tcp_seq) {
1633 3 : if (!(flow_e->fe_tcp_flags &
1634 : VR_FLOW_TCP_ESTABLISHED_R)) {
1635 3 : (void)vr_sync_fetch_and_or_16u(&rflow_e->fe_tcp_flags,
1636 : VR_FLOW_TCP_ESTABLISHED);
1637 3 : flow_tcp_flags = vr_sync_fetch_and_or_16u(
1638 : &flow_e->fe_tcp_flags, VR_FLOW_TCP_ESTABLISHED_R);
1639 3 : if (!(flow_tcp_flags & VR_FLOW_TCP_ESTABLISHED_R) &&
1640 3 : !(flow_tcp_flags & VR_FLOW_TCP_ESTABLISHED)) {
1641 : // If it wasn't established or reverse established,
1642 : // it is being established now. Offload both.
1643 0 : vr_offload_flow_set(flow_e,
1644 : flow_e->fe_hentry.hentry_index, rflow_e);
1645 0 : vr_offload_flow_set(rflow_e,
1646 : rflow_e->fe_hentry.hentry_index, flow_e);
1647 : }
1648 : }
1649 : }
1650 : }
1651 : }
1652 : }
1653 : }
1654 :
1655 14 : return;
1656 : }
1657 :
1658 : static inline bool
1659 5 : vr_flow_vif_allow_new_flow(struct vrouter *router, struct vr_packet *pkt,
1660 : unsigned short *drop_reason)
1661 : {
1662 5 : struct vr_interface *vif_l = NULL;
1663 5 : struct vr_nexthop *nh = NULL;
1664 :
1665 5 : if (vif_is_virtual(pkt->vp_if)) {
1666 3 : vif_l = pkt->vp_if;
1667 2 : } else if (vif_is_fabric(pkt->vp_if)) {
1668 1 : nh = pkt->vp_nh;
1669 1 : if ((nh != NULL) && (nh->nh_flags & NH_FLAG_VALID)) {
1670 1 : vif_l = nh->nh_dev;
1671 : }
1672 : }
1673 :
1674 5 : if (vif_l && vif_drop_new_flows(vif_l)) {
1675 0 : PKT_LOG(VP_DROP_NEW_FLOWS, pkt, 0, VR_FLOW_C, __LINE__);
1676 0 : *drop_reason = VP_DROP_NEW_FLOWS;
1677 0 : return false;
1678 : }
1679 :
1680 5 : return true;
1681 : }
1682 :
1683 : void
1684 0 : vr_flow_get_burst_params(struct vrouter *router, int *burst_tokens,
1685 : int *burst_interval, int *burst_step)
1686 : {
1687 : struct vr_flow_table_info *infop;
1688 :
1689 0 : if (!router || !router->vr_flow_table_info)
1690 0 : return;
1691 :
1692 0 : infop = router->vr_flow_table_info;
1693 :
1694 0 : if (burst_tokens)
1695 0 : *burst_tokens = infop->vfti_burst_tokens_configured;
1696 0 : if (burst_interval)
1697 0 : *burst_interval = infop->vfti_burst_interval_configured;
1698 0 : if (burst_step)
1699 0 : *burst_step = infop->vfti_burst_step_configured;
1700 :
1701 0 : return;
1702 : }
1703 :
1704 : void
1705 0 : vr_flow_set_burst_params(struct vrouter *router, int burst_tokens,
1706 : int burst_interval, int burst_step)
1707 : {
1708 : struct vr_flow_table_info *infop;
1709 :
1710 0 : if (!router || !router->vr_flow_table_info)
1711 0 : return;
1712 :
1713 0 : infop = router->vr_flow_table_info;
1714 :
1715 0 : if (burst_tokens != -1)
1716 0 : infop->vfti_burst_tokens_configured = burst_tokens;
1717 :
1718 0 : if (burst_interval != -1)
1719 0 : infop->vfti_burst_interval_configured = burst_interval;
1720 :
1721 0 : if (burst_step != -1)
1722 0 : infop->vfti_burst_step_configured = burst_step;
1723 :
1724 :
1725 0 : vr_flow_start_burst_processing(router);
1726 0 : return;
1727 : }
1728 :
1729 : static inline unsigned int
1730 0 : vr_flow_burst_count(struct vrouter *router)
1731 : {
1732 0 : struct vr_flow_table_info *infop = router->vr_flow_table_info;
1733 :
1734 0 : return infop->vfti_burst_tokens;
1735 : }
1736 :
1737 : static inline bool
1738 5 : vr_flow_allow_new_flow(struct vrouter *router, struct vr_packet *pkt,
1739 : unsigned short *drop_reason, bool *burst)
1740 : {
1741 : unsigned int hold_count;
1742 5 : struct vr_flow_table_info *infop = router->vr_flow_table_info;
1743 :
1744 5 : *drop_reason = VP_DROP_FLOW_UNUSABLE;
1745 5 : if (burst)
1746 5 : *burst = false;
1747 :
1748 5 : if (pkt->vp_type == VP_TYPE_IP) {
1749 5 : if (!vr_inet_flow_allow_new_flow(router, pkt)) {
1750 0 : PKT_LOG(VP_DROP_FLOW_UNUSABLE, pkt, 0, VR_FLOW_C, __LINE__);
1751 0 : *drop_reason = VP_DROP_FLOW_UNUSABLE;
1752 0 : return false;
1753 : }
1754 : }
1755 :
1756 5 : if (vr_flow_hold_limit) {
1757 5 : hold_count = vr_flow_table_hold_count(router);
1758 5 : if (hold_count > vr_flow_hold_limit) {
1759 0 : if (infop->vfti_burst_used >= vr_flow_burst_count(router)) {
1760 0 : PKT_LOG(VP_DROP_FLOW_UNUSABLE, pkt, 0, VR_FLOW_C, __LINE__);
1761 0 : *drop_reason = VP_DROP_FLOW_UNUSABLE;
1762 0 : return false;
1763 : }
1764 0 : if (burst) {
1765 0 : *burst = true;
1766 : }
1767 : }
1768 : }
1769 :
1770 5 : return vr_flow_vif_allow_new_flow(router, pkt, drop_reason);
1771 : }
1772 :
1773 : static inline struct vr_flow_entry *
1774 5 : vr_flow_new_hold_flow(struct vrouter *router, struct vr_flow *key,
1775 : struct vr_packet *pkt, unsigned int *fe_index,
1776 : struct vr_forwarding_md *fmd) {
1777 : struct vr_flow_entry *bucket_fe, *flow_e;
1778 5 : unsigned short drop_reason = 0;
1779 5 : bool burst = false;
1780 : /* Slow path: lock, to make find+create atomic thus avoid races
1781 : * with another vr_flow_lookup or vr_add_flow). We also need need
1782 : * to retry the find, as previous one was done without locking */
1783 5 : bucket_fe = vr_flow_bucket_first_entry(router, key);
1784 5 : vr_flow_bucket_may_lock(bucket_fe);
1785 5 : flow_e = vr_find_flow(router, key, pkt->vp_type, fe_index);
1786 5 : if (!flow_e) {
1787 5 : if (!vr_flow_allow_new_flow(router, pkt, &drop_reason, &burst)) {
1788 0 : vr_flow_bucket_may_unlock(bucket_fe);
1789 0 : PKT_LOG(drop_reason, pkt, key , VR_FLOW_C, __LINE__);
1790 0 : vr_pfree(pkt, drop_reason);
1791 0 : return flow_e;
1792 : }
1793 :
1794 5 : flow_e = vr_flow_get_free_entry(router, key, pkt->vp_type,
1795 : true, fe_index);
1796 5 : if (!flow_e) {
1797 0 : vr_flow_bucket_may_unlock(bucket_fe);
1798 0 : PKT_LOG(VP_DROP_FLOW_TABLE_FULL, pkt, key, VR_FLOW_C, __LINE__);
1799 0 : vr_pfree(pkt, VP_DROP_FLOW_TABLE_FULL);
1800 0 : return flow_e;
1801 : }
1802 :
1803 5 : flow_e->fe_vrf = fmd->fmd_dvrf;
1804 : /* mark as hold */
1805 5 : vr_flow_entry_set_hold(router, flow_e, burst);
1806 : }
1807 5 : vr_flow_bucket_may_unlock(bucket_fe);
1808 5 : return flow_e;
1809 : }
1810 :
1811 : flow_result_t
1812 67 : vr_flow_lookup(struct vrouter *router, struct vr_flow *key,
1813 : struct vr_packet *pkt, struct vr_forwarding_md *fmd)
1814 : {
1815 : unsigned int fe_index;
1816 : struct vr_flow_entry *flow_e;
1817 67 : pkt->vp_flags |= VP_FLAG_FLOW_SET;
1818 :
1819 67 : if (!fmd->fmd_fe) {
1820 : /* Happy path: without locking */
1821 67 : flow_e = vr_find_flow(router, key, pkt->vp_type, &fe_index);
1822 67 : if (!flow_e) {
1823 5 : if (pkt->vp_nh &&
1824 2 : (pkt->vp_nh->nh_flags &
1825 : (NH_FLAG_RELAXED_POLICY | NH_FLAG_FLOW_LOOKUP)))
1826 0 : return FLOW_FORWARD;
1827 :
1828 5 : flow_e = vr_flow_new_hold_flow(router, key, pkt, &fe_index, fmd);
1829 5 : if (!flow_e)
1830 0 : return FLOW_CONSUMED;
1831 : }
1832 : } else {
1833 0 : flow_e = fmd->fmd_fe;
1834 0 : fe_index = fmd->fmd_flow_index;
1835 : }
1836 :
1837 67 : if (flow_e->fe_flags & VR_FLOW_FLAG_EVICT_CANDIDATE)
1838 0 : return FLOW_EVICT_DROP;
1839 :
1840 : /*
1841 : * Store the source of the packet which gets used incase of Ecmp
1842 : * Source
1843 : */
1844 67 : if (vif_is_fabric(pkt->vp_if))
1845 8 : flow_e->fe_src_info = fmd->fmd_outer_src_ip;
1846 59 : else if (vif_is_virtual(pkt->vp_if))
1847 58 : flow_e->fe_src_info = pkt->vp_if->vif_idx;
1848 :
1849 67 : vr_flow_set_forwarding_md(router, flow_e, fe_index, fmd);
1850 67 : vr_flow_tcp_digest(router, flow_e, pkt, fmd);
1851 :
1852 67 : return vr_do_flow_action(router, flow_e, fe_index, pkt, fmd);
1853 : }
1854 :
1855 : static bool
1856 188 : __vr_flow_forward(flow_result_t result, struct vr_packet *pkt,
1857 : struct vr_forwarding_md *fmd)
1858 : {
1859 188 : bool forward = false;
1860 :
1861 188 : switch (result) {
1862 164 : case FLOW_FORWARD:
1863 164 : forward = true;
1864 164 : break;
1865 :
1866 0 : case FLOW_TRAP:
1867 0 : vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_L3_PROTOCOLS, NULL);
1868 0 : break;
1869 :
1870 0 : case FLOW_EVICT_DROP:
1871 0 : PKT_LOG(VP_DROP_FLOW_EVICT, pkt, 0, VR_FLOW_C, __LINE__);
1872 0 : vr_pfree(pkt, VP_DROP_FLOW_EVICT);
1873 0 : break;
1874 :
1875 24 : case FLOW_HELD:
1876 : case FLOW_CONSUMED:
1877 24 : break;
1878 :
1879 0 : case FLOW_DROP:
1880 : default:
1881 0 : PKT_LOG(VP_DROP_FLOW_UNUSABLE, pkt, 0, VR_FLOW_C, __LINE__);
1882 0 : vr_pfree(pkt, VP_DROP_FLOW_UNUSABLE);
1883 0 : break;
1884 : }
1885 :
1886 188 : return forward;
1887 : }
1888 :
1889 : static bool
1890 20 : vr_flow_is_fat_flow(struct vrouter *router, struct vr_packet *pkt,
1891 : struct vr_flow_entry *fe)
1892 : {
1893 20 : if (pkt->vp_type == VP_TYPE_IP) {
1894 20 : return vr_inet_flow_is_fat_flow(router, pkt, fe);
1895 0 : } else if (pkt->vp_type == VP_TYPE_IP6) {
1896 0 : return vr_inet6_flow_is_fat_flow(router, pkt, fe);
1897 : }
1898 :
1899 0 : return false;
1900 : }
1901 :
1902 : uint16_t
1903 59 : vr_flow_fat_flow_lookup(struct vrouter *router, struct vr_packet *pkt,
1904 : uint16_t l4_proto, uint16_t sport, uint16_t dport,
1905 : unsigned int *saddr, unsigned int *daddr,
1906 : unsigned char *ip6_src, unsigned char *ip6_dst)
1907 : {
1908 59 : uint8_t fat_flow_mask, tmp_mask = 0;
1909 : struct vr_nexthop *nh;
1910 59 : struct vr_interface *vif_l = NULL;
1911 :
1912 59 : if (vif_is_virtual(pkt->vp_if)) {
1913 49 : vif_l = pkt->vp_if;
1914 10 : } else if (vif_is_fabric(pkt->vp_if)) {
1915 8 : if ((nh = pkt->vp_nh) && (nh->nh_flags & NH_FLAG_VALID)) {
1916 : /* In case of ECMP, check the vif within the ECMP member NH */
1917 8 : if (vr_is_local_ecmp_nh(nh)) {
1918 0 : vif_l = vr_get_ecmp_first_member_dev(nh);
1919 : } else {
1920 8 : vif_l = nh->nh_dev;
1921 : }
1922 : }
1923 : }
1924 :
1925 59 : if (!vif_l)
1926 2 : return VR_FAT_FLOW_NO_MASK;
1927 :
1928 57 : fat_flow_mask = vif_fat_flow_lookup((pkt->vp_if == vif_l), vif_l, l4_proto, sport, dport,
1929 : saddr, daddr, ip6_src, ip6_dst);
1930 57 : if (pkt->vp_if != vif_l) {
1931 :
1932 8 : if (fat_flow_mask & VR_FAT_FLOW_SRC_IP_MASK)
1933 0 : tmp_mask |= VR_FAT_FLOW_DST_IP_MASK;
1934 :
1935 8 : if (fat_flow_mask & VR_FAT_FLOW_DST_IP_MASK)
1936 0 : tmp_mask |= VR_FAT_FLOW_SRC_IP_MASK;
1937 :
1938 8 : fat_flow_mask &= ~(VR_FAT_FLOW_DST_IP_MASK |
1939 : VR_FAT_FLOW_SRC_IP_MASK);
1940 :
1941 :
1942 8 : fat_flow_mask |= tmp_mask;
1943 :
1944 : }
1945 :
1946 57 : return fat_flow_mask;
1947 : }
1948 :
1949 : static flow_result_t
1950 170 : vr_do_flow_lookup(struct vrouter *router, struct vr_packet *pkt,
1951 : struct vr_forwarding_md *fmd)
1952 : {
1953 170 : flow_result_t result = FLOW_FORWARD;
1954 :
1955 : /* Flow processing is only for untagged unicast IP packets */
1956 170 : if (pkt->vp_type == VP_TYPE_IP)
1957 156 : result = vr_inet_flow_lookup(router, pkt, fmd);
1958 14 : else if (pkt->vp_type == VP_TYPE_IP6)
1959 10 : result = vr_inet6_flow_lookup(router, pkt, fmd);
1960 :
1961 170 : return result;
1962 : }
1963 :
1964 : static void
1965 8 : vr_reinit_forwarding_md(struct vrouter *router, struct vr_packet *pkt,
1966 : struct vr_flow_entry *fe, uint32_t flow_index,
1967 : struct vr_nexthop *nh, struct vr_forwarding_md *fmd)
1968 : {
1969 : int i;
1970 8 : struct vr_nexthop *src_nh = __vrouter_get_nexthop(router, fe->fe_src_nh_index);
1971 :
1972 8 : for (i = 0; i < VR_MAX_PHY_INF; i++) {
1973 8 : if (nh->nh_dev_arr[i] != NULL) {
1974 8 : fmd->fmd_dvrf = nh->nh_dev_arr[i]->vif_vrf;
1975 8 : break;
1976 : }
1977 : }
1978 :
1979 8 : fmd->fmd_vlan = 0;
1980 8 : fmd->fmd_dotonep = -1;
1981 8 : fmd->fmd_outer_src_ip = src_nh->nh_udp_tun_dip;
1982 8 : vr_flow_set_forwarding_md(router, fe, flow_index, fmd);
1983 8 : }
1984 :
1985 : bool
1986 186 : vr_flow_forward(struct vrouter *router, struct vr_packet *pkt,
1987 : struct vr_forwarding_md *fmd)
1988 : {
1989 186 : flow_result_t result = FLOW_FORWARD;
1990 :
1991 186 : if (vif_is_hbs_right(pkt->vp_if)) {
1992 : /* Pkt entering vrouter from hbs-r
1993 : * - If SMAC has magic, Restore actual SMAC from flow_index and continue
1994 : * - If DMAC has magic, Restore actual DMAC from flow_index and continue
1995 : */
1996 4 : struct vr_eth_hbs_md *eth_hbs = (struct vr_eth_hbs_md*)pkt_data(pkt);
1997 4 : struct vr_eth *eth = (struct vr_eth*)pkt_data(pkt);
1998 : uint16_t magic;
1999 : unsigned int flow_index;
2000 : uint32_t nh_id;
2001 4 : struct vr_flow_entry *fe = NULL;
2002 : unsigned char* mac;
2003 4 : if ((ntohs(eth_hbs->magic_smac) & VR_HBS_MAGIC_MASK) ==
2004 : VR_HBS_SMAC_MAGIC) {
2005 4 : magic = VR_HBS_SMAC_MAGIC;
2006 4 : flow_index = ntohl(eth_hbs->flow_id_smac);
2007 4 : mac = eth->eth_smac;
2008 0 : } else if ((ntohs(eth_hbs->magic_dmac) & VR_HBS_MAGIC_MASK) ==
2009 : VR_HBS_DMAC_MAGIC) {
2010 0 : magic = VR_HBS_DMAC_MAGIC;
2011 0 : flow_index = ntohl(eth_hbs->flow_id_dmac);
2012 0 : mac = eth->eth_dmac;
2013 : } else {
2014 0 : PKT_LOG(VP_DROP_INVALID_HBS_PKT, pkt, 0, VR_FLOW_C, __LINE__);
2015 0 : goto drop_pkt;
2016 : }
2017 :
2018 4 : if (vr_htable_get_hentry_by_index(router->vr_flow_table, flow_index)) {
2019 : struct vr_nexthop *nh;
2020 4 : fe = CONTAINER_OF(
2021 : fe_hentry,
2022 : struct vr_flow_entry,
2023 : vr_htable_get_hentry_by_index(
2024 : router->vr_flow_table, flow_index)
2025 : );
2026 4 : nh_id = fe->fe_key.flow_nh_id;
2027 4 : nh = vrouter_get_nexthop(0, nh_id);
2028 4 : vr_reinit_forwarding_md(router, pkt, fe, flow_index, nh, fmd);
2029 :
2030 4 : if(fe->fe_underlay_ecmp_index >= 0) {
2031 0 : if(nh->nh_type == NH_TUNNEL) {
2032 0 : pkt->vp_if = __vrouter_get_interface(router,
2033 0 : fe->fe_underlay_ecmp_index);
2034 : } else
2035 0 : pkt->vp_if = nh->nh_dev;
2036 : } else
2037 4 : pkt->vp_if = nh->nh_dev;
2038 :
2039 4 : memcpy(mac, nh->nh_data, VR_ETHER_ALEN);
2040 4 : result = vr_flow_action_default(router, fe, flow_index, pkt, fmd);
2041 4 : return __vr_flow_forward(result, pkt, fmd);
2042 : }
2043 182 : } else if (vif_is_hbs_left(pkt->vp_if)) {
2044 : /* Pkt entering vrouter from hbs-l
2045 : * - DMAC of the packet contains flow_index
2046 : * - Restore actual DMAC from flow_index and continue
2047 : * flow action
2048 : * If VR_HBS_FROM_VMI is set in the DMAC -
2049 : * - The packet originated from VMI (instead of fabric)
2050 : * - Happens if both src and dst tenant VMs are in
2051 : * the same compute (intra-compute case)
2052 : * - Restore actual DMAC from "reverse flow_index"
2053 : */
2054 4 : struct vr_eth *eth = (struct vr_eth*)pkt_data(pkt);
2055 4 : struct vr_eth_hbs_md *eth_hbs = (struct vr_eth_hbs_md*)pkt_data(pkt);
2056 4 : uint16_t magic = ntohs(eth_hbs->magic_dmac);
2057 4 : unsigned int flow_index = ntohl(eth_hbs->flow_id_dmac);
2058 : uint32_t nh_id;
2059 4 : struct vr_flow_entry *fe = NULL;
2060 4 : if ((magic & VR_HBS_MAGIC_MASK) != VR_HBS_DMAC_MAGIC) {
2061 0 : PKT_LOG(VP_DROP_INVALID_HBS_PKT, pkt, 0, VR_FLOW_C, __LINE__);
2062 0 : goto drop_pkt;
2063 : }
2064 :
2065 4 : if (vr_htable_get_hentry_by_index(router->vr_flow_table, flow_index)) {
2066 : struct vr_nexthop *nh;
2067 4 : fe = CONTAINER_OF(
2068 : fe_hentry,
2069 : struct vr_flow_entry,
2070 : vr_htable_get_hentry_by_index(
2071 : router->vr_flow_table, flow_index)
2072 : );
2073 : /* If packet is coming from VMI instead of fabric,
2074 : * restore DMAC using reverse flow
2075 : */
2076 4 : if (magic & VR_HBS_FROM_VMI) {
2077 2 : flow_index = fe->fe_rflow;
2078 2 : fe = vr_flow_get_entry(router, fe->fe_rflow);
2079 2 : if (!fe) {
2080 0 : PKT_LOG(VP_DROP_INVALID_HBS_PKT, pkt, 0, VR_FLOW_C, __LINE__);
2081 0 : goto drop_pkt;
2082 : }
2083 : }
2084 :
2085 4 : nh_id = fe->fe_key.flow_nh_id;
2086 4 : nh = vrouter_get_nexthop(0, nh_id);
2087 4 : vr_reinit_forwarding_md(router, pkt, fe, flow_index, nh, fmd);
2088 :
2089 4 : if(fe->fe_underlay_ecmp_index >= 0) {
2090 0 : if(nh->nh_type == NH_TUNNEL) {
2091 0 : pkt->vp_if = __vrouter_get_interface(router,
2092 0 : fe->fe_underlay_ecmp_index);
2093 : } else
2094 0 : pkt->vp_if = nh->nh_dev;
2095 : } else
2096 4 : pkt->vp_if = nh->nh_dev;
2097 :
2098 4 : if (magic & VR_HBS_L3_PKT)
2099 0 : memcpy(eth->eth_dmac, pkt->vp_if->vif_mac, VR_ETHER_ALEN);
2100 : else
2101 4 : memcpy(eth->eth_dmac, nh->nh_data, VR_ETHER_ALEN);
2102 4 : result = vr_flow_action_default(router, fe, flow_index, pkt, fmd);
2103 4 : return __vr_flow_forward(result, pkt, fmd);
2104 : }
2105 178 : } else if ((!(pkt->vp_flags & VP_FLAG_MULTICAST))
2106 178 : && ((fmd->fmd_vlan == VLAN_ID_INVALID) || vif_is_service(pkt->vp_if)))
2107 170 : result = vr_do_flow_lookup(router, pkt, fmd);
2108 :
2109 178 : return __vr_flow_forward(result, pkt, fmd);
2110 :
2111 0 : drop_pkt:
2112 0 : vr_pfree(pkt, VP_DROP_INVALID_HBS_PKT);
2113 0 : return false;
2114 : }
2115 :
2116 : int
2117 29 : vr_flow_flush_pnode(struct vrouter *router, struct vr_packet_node *pnode,
2118 : struct vr_flow_entry *fe, struct vr_forwarding_md *fmd)
2119 : {
2120 : bool forward;
2121 :
2122 : struct vr_interface *vif;
2123 : struct vr_packet *pkt;
2124 : struct vr_ip *ip;
2125 : struct vr_ip6 *ip6;
2126 : flow_result_t result;
2127 :
2128 29 : fmd->fmd_outer_src_ip = pnode->pl_outer_src_ip;
2129 29 : if (pnode->pl_flags & PN_FLAG_LABEL_IS_VXLAN_ID) {
2130 0 : vr_fmd_set_label(fmd, pnode->pl_label,
2131 : VR_LABEL_TYPE_VXLAN_ID);
2132 : } else {
2133 29 : vr_fmd_set_label(fmd, pnode->pl_label,
2134 : VR_LABEL_TYPE_MPLS);
2135 : }
2136 :
2137 29 : if (pnode->pl_flags & PN_FLAG_TO_ME)
2138 0 : fmd->fmd_to_me = 1;
2139 :
2140 29 : pkt = pnode->pl_packet;
2141 29 : if (!pkt)
2142 14 : return -EINVAL;
2143 :
2144 15 : fmd->fmd_dscp = pnode->pl_dscp;
2145 15 : fmd->fmd_dotonep = pnode->pl_dotonep;
2146 15 : fmd->fmd_vlan = pnode->pl_vlan;
2147 15 : fmd->fmd_mirror_data = pnode->pl_mirror_vlan;
2148 :
2149 15 : pnode->pl_packet = NULL;
2150 : /*
2151 : * this is only a security check and not a catch all check. one note
2152 : * of caution. please do not access pkt->vp_if till the if block is
2153 : * succesfully bypassed
2154 : */
2155 15 : vif = __vrouter_get_interface(router, pnode->pl_vif_idx);
2156 15 : if (!vif || (pkt->vp_if != vif)) {
2157 5 : pkt->vp_if = NULL;
2158 5 : PKT_LOG(VP_DROP_INVALID_IF, pkt, 0, VR_FLOW_C, __LINE__);
2159 5 : vr_pfree(pkt, VP_DROP_INVALID_IF);
2160 5 : return -ENODEV;
2161 : }
2162 :
2163 10 : if (!pkt->vp_nh) {
2164 10 : if (vif_is_fabric(pkt->vp_if) && fmd &&
2165 1 : (fmd->fmd_label >= 0)) {
2166 1 : if (!vr_fmd_label_is_vxlan_id(fmd)) {
2167 1 : pkt->vp_nh = __vrouter_get_label(router, fmd->fmd_label);
2168 : } else {
2169 0 : pkt->vp_nh = __vrouter_bridge_lookup(fmd->fmd_dvrf,
2170 : pkt_data(pkt));
2171 : }
2172 : }
2173 10 : if(vif_is_vhost(vif) && !(vif->vif_flags & VIF_FLAG_POLICY_ENABLED)) {
2174 1 : if (pkt->vp_type == VP_TYPE_IP) {
2175 1 : ip = (struct vr_ip *) pkt_network_header(pkt);
2176 1 : pkt->vp_nh = vr_inet_ip_lookup(pnode->pl_vrf, ip->ip_daddr);
2177 0 : } else if (pkt->vp_type == VP_TYPE_IP6) {
2178 0 : ip6 = (struct vr_ip6 *) pkt_network_header(pkt);
2179 0 : pkt->vp_nh = vr_inet6_ip_lookup(pnode->pl_vrf, ip6->ip6_dst);
2180 : }
2181 : }
2182 : }
2183 :
2184 10 : if (fe) {
2185 2 : result = vr_flow_action(router, fe, fmd->fmd_flow_index, pkt, fmd);
2186 2 : forward = __vr_flow_forward(result, pkt, fmd);
2187 : } else {
2188 8 : forward = vr_flow_forward(router, pkt, fmd);
2189 : }
2190 :
2191 10 : if (forward)
2192 9 : vr_reinject_packet(pkt, fmd);
2193 :
2194 10 : return 0;
2195 : }
2196 :
2197 : static void
2198 7 : __vr_flow_flush_hold_queue(struct vrouter *router, struct vr_flow_entry *fe,
2199 : struct vr_forwarding_md *fmd, struct vr_flow_queue *vfq)
2200 : {
2201 : unsigned int i;
2202 : struct vr_packet_node *pnode;
2203 :
2204 28 : for (i = 0; i < VR_MAX_FLOW_QUEUE_ENTRIES; i++) {
2205 21 : pnode = &vfq->vfq_pnodes[i];
2206 21 : vr_flow_flush_pnode(router, pnode, fe, fmd);
2207 : }
2208 :
2209 7 : return;
2210 : }
2211 :
2212 : static void
2213 329 : vr_flush_entry(struct vrouter *router, struct vr_flow_entry *fe,
2214 : struct vr_flow_md *flmd, struct vr_forwarding_md *fmd)
2215 : {
2216 : bool swapped;
2217 :
2218 : struct vr_flow_queue *vfq;
2219 329 : struct vr_defer_data *vdd = flmd->flmd_defer_data;
2220 : struct vr_flow_defer_data *vfdd;
2221 :
2222 329 : vfq = fe->fe_hold_list;
2223 329 : if (vfq) {
2224 5 : if (fe->fe_action == VR_FLOW_ACTION_HOLD)
2225 0 : return;
2226 :
2227 5 : swapped = vr_sync_bool_compare_and_swap_p(&fe->fe_hold_list, vfq, NULL);
2228 5 : if (swapped) {
2229 5 : __vr_flow_flush_hold_queue(router, fe, fmd, vfq);
2230 5 : if (!vdd || !vdd->vdd_data)
2231 3 : goto free_flush_queue;
2232 :
2233 2 : vfdd = (struct vr_flow_defer_data *)vdd->vdd_data;
2234 2 : vfdd->vfdd_flow_queue = vfq;
2235 : }
2236 : }
2237 :
2238 326 : return;
2239 :
2240 3 : free_flush_queue:
2241 3 : if (vfq)
2242 3 : vr_free(vfq, VR_FLOW_QUEUE_OBJECT);
2243 3 : return;
2244 : }
2245 :
2246 : static void
2247 318 : __vr_flow_work(struct vrouter *router, struct vr_flow_entry *fe,
2248 : struct vr_flow_md *flmd)
2249 : {
2250 : struct vr_forwarding_md fmd;
2251 :
2252 318 : vr_init_forwarding_md(&fmd);
2253 318 : vr_flow_set_forwarding_md(router, fe, flmd->flmd_index, &fmd);
2254 318 : vr_flush_entry(router, fe, flmd, &fmd);
2255 :
2256 318 : vr_flow_defer(flmd, fe);
2257 318 : return;
2258 : }
2259 :
2260 :
2261 : static void
2262 318 : vr_flow_work(void *arg)
2263 : {
2264 : struct vrouter *router;
2265 : struct vr_flow_entry *fe;
2266 318 : struct vr_flow_md *flmd =
2267 : (struct vr_flow_md *)arg;
2268 :
2269 318 : router = flmd->flmd_router;
2270 318 : if (!router)
2271 0 : goto exit_flush;
2272 :
2273 318 : fe = vr_flow_get_entry(router, flmd->flmd_index);
2274 318 : if (!fe)
2275 0 : goto exit_flush;
2276 :
2277 318 : __vr_flow_work(router, fe, flmd);
2278 :
2279 318 : exit_flush:
2280 318 : if (flmd->flmd_defer_data) {
2281 0 : if (flmd->flmd_defer_data->vdd_data) {
2282 0 : vr_free(flmd->flmd_defer_data->vdd_data,
2283 : VR_FLOW_DEFER_DATA_OBJECT);
2284 : }
2285 0 : vr_put_defer_data(flmd->flmd_defer_data);
2286 0 : flmd->flmd_defer_data = NULL;
2287 : }
2288 :
2289 318 : vr_free(flmd, VR_FLOW_METADATA_OBJECT);
2290 :
2291 318 : return;
2292 : }
2293 :
2294 : static void
2295 216 : vr_flow_set_mirror(struct vrouter *router, vr_flow_req *req,
2296 : struct vr_flow_entry *fe)
2297 : {
2298 216 : struct vr_mirror_entry *mirror = NULL, *sec_mirror = NULL;
2299 :
2300 216 : if (!(req->fr_flags & VR_FLOW_FLAG_MIRROR) &&
2301 214 : (fe->fe_flags & VR_FLOW_FLAG_MIRROR)) {
2302 0 : vr_flow_reset_mirror(router, fe, req->fr_index);
2303 0 : return;
2304 : }
2305 :
2306 216 : if (!(req->fr_flags & VR_FLOW_FLAG_MIRROR))
2307 214 : return;
2308 :
2309 2 : if (fe->fe_mirror_id != req->fr_mir_id) {
2310 2 : if (fe->fe_mirror_id < router->vr_max_mirror_indices) {
2311 0 : fe->fe_mirror_id = router->vr_max_mirror_indices;
2312 : }
2313 :
2314 2 : if ((unsigned int)req->fr_mir_id < router->vr_max_mirror_indices) {
2315 2 : mirror = vrouter_get_mirror(req->fr_rid, req->fr_mir_id);
2316 2 : if (mirror)
2317 2 : fe->fe_mirror_id = req->fr_mir_id;
2318 :
2319 : /* when we reached this point, we had already done all the
2320 : * sanity checks we could do. failing here will add only
2321 : * complexity to code here. so !mirror case, we will not
2322 : * handle
2323 : */
2324 : }
2325 : }
2326 :
2327 2 : if (fe->fe_sec_mirror_id != req->fr_sec_mir_id) {
2328 2 : if (fe->fe_sec_mirror_id < router->vr_max_mirror_indices) {
2329 0 : fe->fe_sec_mirror_id = router->vr_max_mirror_indices;
2330 : }
2331 :
2332 2 : if ((unsigned int)req->fr_sec_mir_id < router->vr_max_mirror_indices) {
2333 2 : sec_mirror = vrouter_get_mirror(req->fr_rid, req->fr_sec_mir_id);
2334 2 : if (sec_mirror)
2335 0 : fe->fe_sec_mirror_id = req->fr_sec_mir_id;
2336 : }
2337 : }
2338 :
2339 2 : if (req->fr_pcap_meta_data_size && req->fr_pcap_meta_data) {
2340 0 : if (fe->fe_mme) {
2341 0 : vr_mirror_meta_entry_del(router, fe->fe_mme);
2342 0 : fe->fe_mme = NULL;
2343 : }
2344 :
2345 0 : fe->fe_mme = vr_mirror_meta_entry_set(router, req->fr_index,
2346 0 : req->fr_mir_sip, req->fr_mir_sport,
2347 0 : req->fr_pcap_meta_data, req->fr_pcap_meta_data_size,
2348 0 : req->fr_mir_vrf);
2349 :
2350 0 : if (fe->fe_mme) {
2351 0 : vr_offload_flow_meta_data_set(req->fr_index,
2352 : req->fr_pcap_meta_data_size,
2353 0 : req->fr_pcap_meta_data,
2354 0 : req->fr_mir_vrf);
2355 : }
2356 : }
2357 :
2358 2 : return;
2359 : }
2360 :
2361 : void
2362 184 : vr_fill_flow_common(struct vr_flow *flowp, unsigned int nh_id,
2363 : uint8_t proto, uint16_t sport, uint16_t dport, uint8_t family,
2364 : uint8_t valid_fkey_params)
2365 : {
2366 184 : flowp->flow_nh_id = nh_id;
2367 184 : flowp->flow_family = family;
2368 184 : if (family == AF_INET)
2369 174 : flowp->flow_key_len = VR_FLOW_IPV4_HASH_SIZE;
2370 : else
2371 10 : flowp->flow_key_len = VR_FLOW_IPV6_HASH_SIZE;
2372 184 : flowp->flow_unused = 0;
2373 :
2374 184 : if (valid_fkey_params & VR_FLOW_KEY_PROTO)
2375 184 : flowp->flow_proto = proto;
2376 :
2377 184 : if (valid_fkey_params & VR_FLOW_KEY_SRC_PORT)
2378 184 : flowp->flow_sport = sport;
2379 :
2380 184 : if (valid_fkey_params & VR_FLOW_KEY_DST_PORT)
2381 184 : flowp->flow_dport = dport;
2382 :
2383 184 : return;
2384 : }
2385 :
2386 : static struct vr_flow_entry *
2387 104 : vr_add_flow(unsigned int rid, struct vr_flow *key, uint8_t type,
2388 : bool need_hold_queue, unsigned int *fe_index,
2389 : uint8_t *fe_gen_id)
2390 : {
2391 : struct vr_flow_entry *flow_e;
2392 104 : struct vrouter *router = vrouter_get(rid);
2393 :
2394 104 : struct vr_flow_entry *bucket_fe = vr_flow_bucket_first_entry(router, key);
2395 104 : vr_flow_bucket_may_lock(bucket_fe);
2396 104 : flow_e = vr_find_flow(router, key, type, fe_index);
2397 104 : if (flow_e) {
2398 0 : vr_flow_bucket_may_unlock(bucket_fe);
2399 0 : *fe_gen_id = flow_e->fe_gen_id;
2400 : /* a race between agent and dp. allow agent to handle this error */
2401 0 : return NULL;
2402 : } else {
2403 104 : flow_e = vr_flow_get_free_entry(router, key, type,
2404 : need_hold_queue, fe_index);
2405 104 : vr_flow_bucket_may_unlock(bucket_fe);
2406 : }
2407 :
2408 104 : return flow_e;
2409 : }
2410 :
2411 : static struct vr_flow_entry *
2412 104 : vr_add_flow_req(vr_flow_req *req, unsigned int *fe_index, uint8_t *fe_gen_id)
2413 : {
2414 : uint8_t type;
2415 104 : bool need_hold_queue = false;
2416 :
2417 : struct vr_flow key;
2418 : struct vr_flow_entry *fe;
2419 :
2420 104 : switch (req->fr_family) {
2421 6 : case AF_INET6:
2422 6 : type = VP_TYPE_IP6;
2423 6 : vr_inet6_fill_flow_from_req(&key, req);
2424 6 : break;
2425 :
2426 98 : case AF_INET:
2427 98 : type = VP_TYPE_IP;
2428 98 : vr_inet_fill_flow(&key, req->fr_flow_nh_id,
2429 98 : (uint32_t)req->fr_flow_sip_l, (uint32_t)req->fr_flow_dip_l,
2430 98 : req->fr_flow_proto, req->fr_flow_sport, req->fr_flow_dport,
2431 : VR_FLOW_KEY_ALL);
2432 98 : break;
2433 :
2434 0 : default:
2435 0 : return NULL;
2436 : }
2437 :
2438 104 : if (req->fr_action == VR_FLOW_ACTION_HOLD)
2439 0 : need_hold_queue = true;
2440 :
2441 104 : fe = vr_add_flow(req->fr_rid, &key, type, need_hold_queue, fe_index,
2442 : fe_gen_id);
2443 104 : if (fe)
2444 104 : req->fr_index = *fe_index;
2445 :
2446 104 : return fe;
2447 : }
2448 :
2449 : /*
2450 : * can be called with 'fe' as null (specifically when flow is added from
2451 : * agent), in which case we should be checking only the request
2452 : */
2453 : static int
2454 322 : vr_flow_set_req_is_invalid(struct vrouter *router, vr_flow_req *req,
2455 : struct vr_flow_entry *fe)
2456 : {
2457 322 : int error = 0, key_type;
2458 : struct vr_flow_entry *rfe;
2459 : struct vr_flow key;
2460 : uint64_t *ip;
2461 :
2462 322 : if (fe) {
2463 :
2464 : /* If Delete marked, dont allow any other change */
2465 210 : if (fe->fe_flags & VR_FLOW_FLAG_DELETE_MARKED)
2466 0 : return -EINVAL;
2467 :
2468 210 : if ((fe->fe_type == VP_TYPE_IP) || (fe->fe_type == VP_TYPE_IP6)) {
2469 210 : if ((uint8_t)req->fr_gen_id != fe->fe_gen_id) {
2470 0 : error = -EBADF;
2471 0 : goto invalid_req;
2472 : }
2473 :
2474 : /*
2475 : * when gen id is same flow keys should not mis-match
2476 : * send EFAULT if such incident happens
2477 : */
2478 210 : if((unsigned short)req->fr_flow_sport != fe->fe_key.flow_sport ||
2479 210 : (unsigned short)req->fr_flow_dport != fe->fe_key.flow_dport||
2480 210 : (uint32_t) req->fr_flow_nh_id != (uint32_t) fe->fe_key.flow_nh_id ||
2481 210 : (unsigned char)req->fr_flow_proto != fe->fe_key.flow_proto) {
2482 0 : error = -EFAULT;
2483 0 : goto invalid_req;
2484 : }
2485 :
2486 210 : if (fe->fe_type == VP_TYPE_IP) {
2487 200 : if ((fe->fe_key.flow4_sip != (uint32_t)req->fr_flow_sip_l) ||
2488 200 : (fe->fe_key.flow4_dip != (uint32_t)req->fr_flow_dip_l)) {
2489 0 : error = -EFAULT;
2490 0 : goto invalid_req;
2491 : }
2492 : } else {
2493 10 : ip = (uint64_t *)fe->fe_key.flow6_sip;
2494 10 : if ((*ip != req->fr_flow_sip_u) ||
2495 10 : (*(ip+1) != req->fr_flow_sip_l) ||
2496 10 : (*(ip+2) != req->fr_flow_dip_u) ||
2497 10 : (*(ip+3) != req->fr_flow_dip_l)) {
2498 0 : error = -EFAULT;
2499 0 : goto invalid_req;
2500 : }
2501 : }
2502 : }
2503 : } else {
2504 : /*
2505 : * flow set request received with an index which is
2506 : * not active anymore, return ENOENT error
2507 : */
2508 112 : if ((req->fr_flags & VR_FLOW_FLAG_ACTIVE) && !(req->fr_index < 0)) {
2509 0 : error = -ENOENT;
2510 0 : goto invalid_req;
2511 : }
2512 : }
2513 :
2514 322 : if (req->fr_flags & VR_FLOW_FLAG_VRFT) {
2515 12 : if ((unsigned short)req->fr_flow_dvrf >= router->vr_max_vrfs) {
2516 0 : error = -EINVAL;
2517 0 : goto invalid_req;
2518 : }
2519 : }
2520 :
2521 322 : if (req->fr_flags & VR_FLOW_FLAG_MIRROR) {
2522 2 : if (((unsigned int)req->fr_mir_id >= router->vr_max_mirror_indices) &&
2523 0 : (unsigned int)req->fr_sec_mir_id >= router->vr_max_mirror_indices) {
2524 0 : error = -EINVAL;
2525 0 : goto invalid_req;
2526 : }
2527 : }
2528 :
2529 322 : if (req->fr_flags & VR_RFLOW_VALID) {
2530 160 : if (req->fr_rindex != -1) {
2531 160 : rfe = vr_flow_get_entry(router, req->fr_rindex);
2532 : } else {
2533 0 : if (req->fr_family == AF_INET) {
2534 0 : vr_inet_fill_flow(&key, req->fr_rflow_nh_id,
2535 0 : (uint32_t)req->fr_rflow_sip_l, (uint32_t)req->fr_rflow_dip_l,
2536 0 : req->fr_flow_proto, req->fr_rflow_sport,
2537 0 : req->fr_rflow_dport, VR_FLOW_KEY_ALL);
2538 :
2539 0 : key_type = VP_TYPE_IP;
2540 : } else {
2541 0 : vr_inet6_fill_rflow_from_req(&key, req);
2542 0 : key_type = VP_TYPE_IP6;
2543 : }
2544 :
2545 0 : rfe = vr_find_flow(router, &key, key_type, &req->fr_rindex);
2546 : }
2547 :
2548 160 : if (!rfe) {
2549 0 : error = -EINVAL;
2550 0 : goto invalid_req;
2551 : }
2552 : }
2553 :
2554 322 : return 0;
2555 :
2556 0 : invalid_req:
2557 0 : return error;
2558 : }
2559 :
2560 : static int
2561 318 : __vr_flow_schedule_transition(struct vrouter *router, struct vr_flow_entry *fe,
2562 : unsigned int index, unsigned short flags)
2563 : {
2564 : struct vr_flow_md *flmd;
2565 318 : struct vr_defer_data *defer = NULL;
2566 318 : struct vr_flow_entry *rfe = NULL;
2567 :
2568 318 : flmd = (struct vr_flow_md *)vr_malloc(sizeof(*flmd),
2569 : VR_FLOW_METADATA_OBJECT);
2570 318 : if (!flmd)
2571 0 : return -ENOMEM;
2572 :
2573 318 : flmd->flmd_router = router;
2574 318 : flmd->flmd_index = index;
2575 318 : flmd->flmd_flags = flags;
2576 318 : if (fe->fe_hold_list || (flags & VR_FLOW_FLAG_EVICT_CANDIDATE)) {
2577 6 : defer = vr_get_defer_data(sizeof(*defer));
2578 6 : if (defer) {
2579 6 : defer->vdd_data = (void *)vr_zalloc(sizeof(struct vr_flow_defer_data),
2580 : VR_FLOW_DEFER_DATA_OBJECT);
2581 6 : if (!(flmd->flmd_flags & VR_FLOW_FLAG_ACTIVE)) {
2582 0 : ((struct vr_flow_defer_data *)defer->vdd_data)->vfdd_delete =
2583 : true;
2584 : }
2585 : /*
2586 : * Set vfdd_evict_flow to true only if there is only one flow
2587 : * or both flows have EVICT_CANDIDATE flag set;
2588 : * This is to avoid a race condition which can lead to non
2589 : * eviction of one of the flows. See CEM-4275 for more details.
2590 : *
2591 : * CEM-18166: Handle a corner case for BGPaaS where two different
2592 : * flows are trapped to agent (due to NAT translation to the same
2593 : * port), combined with TCP RST/FIN pkts received on the reverse
2594 : * flow. The sequence of events permits deletion of the FF, while
2595 : * RF still pointing to it. When the Controller tries to reset the
2596 : * connection, thus causing eviction the flow, vrouter will fail
2597 : * because rfe for the RF is NULL.
2598 : */
2599 6 : if ((fe->fe_flags & VR_FLOW_FLAG_EVICT_CANDIDATE)) {
2600 8 : if ((fe->fe_rflow < 0) ||
2601 4 : ((rfe = vr_flow_get_entry(router, fe->fe_rflow)) &&
2602 4 : (rfe->fe_flags & VR_FLOW_FLAG_EVICT_CANDIDATE)) || !rfe) {
2603 4 : ((struct vr_flow_defer_data *)defer->vdd_data)->vfdd_evict_flow =
2604 : true;
2605 : }
2606 : }
2607 : }
2608 : }
2609 318 : flmd->flmd_defer_data = defer;
2610 :
2611 318 : return vr_schedule_work(vr_get_cpu(), vr_flow_work, (void *)flmd);
2612 : }
2613 :
2614 : static int
2615 314 : vr_flow_schedule_transition(struct vrouter *router, vr_flow_req *req,
2616 : struct vr_flow_entry *fe)
2617 : {
2618 314 : return __vr_flow_schedule_transition(router, fe, req->fr_index, req->fr_flags);
2619 : }
2620 :
2621 : static int
2622 98 : vr_flow_delete(struct vrouter *router, vr_flow_req *req,
2623 : struct vr_flow_entry *fe)
2624 : {
2625 98 : int port = 0;
2626 : /* Delete Mark it */
2627 98 : fe->fe_flags |= VR_FLOW_FLAG_DELETE_MARKED;
2628 :
2629 :
2630 98 : if (fe->fe_flags & VR_FLOW_FLAG_LINK_LOCAL) {
2631 3 : if (fe->fe_key.flow_proto == VR_IP_PROTO_ICMP) {
2632 : /*
2633 : * ICMP id passed as source port would be
2634 : * used for relaxed policy flow lookup
2635 : */
2636 1 : port = ntohs(fe->fe_key.flow_sport);
2637 : } else {
2638 2 : port = ntohs(fe->fe_key.flow_dport);
2639 : }
2640 3 : vr_clear_link_local_port(router, AF_INET, fe->fe_key.flow_proto, port);
2641 : }
2642 :
2643 98 : fe->fe_action = VR_FLOW_ACTION_DROP;
2644 98 : vr_flow_reset_mirror(router, fe, req->fr_index);
2645 98 : return vr_flow_schedule_transition(router, req, fe);
2646 : }
2647 :
2648 : static void
2649 216 : vr_flow_udp_src_port (struct vrouter *router, struct vr_flow_entry *fe)
2650 : {
2651 : uint32_t hash_key[10], hashval, port_range, hash_len;
2652 : uint16_t port;
2653 :
2654 216 : if (fe->fe_udp_src_port)
2655 110 : return;
2656 :
2657 106 : if (hashrnd_inited == 0) {
2658 33 : get_random_bytes(&vr_hashrnd, sizeof(vr_hashrnd));
2659 33 : hashrnd_inited = 1;
2660 : }
2661 :
2662 106 : hash_key[0] = fe->fe_vrf;
2663 106 : hash_key[1] = (fe->fe_key.flow_sport << 16) | fe->fe_key.flow_dport;
2664 106 : memcpy(&hash_key[2], fe->fe_key.flow_ip, 2 * VR_IP_ADDR_SIZE(fe->fe_type));
2665 106 : hash_len = VR_FLOW_HASH_SIZE(fe->fe_type);
2666 :
2667 106 : hashval = vr_hash(hash_key, hash_len, vr_hashrnd);
2668 106 : port_range = VR_MUDP_PORT_RANGE_END - VR_MUDP_PORT_RANGE_START;
2669 106 : port = (uint16_t ) (((uint64_t ) hashval * port_range) >> 32);
2670 :
2671 106 : if (port > port_range) {
2672 : /*
2673 : * Shouldn't happen...
2674 : */
2675 0 : port = 0;
2676 : }
2677 106 : fe->fe_udp_src_port = port + VR_MUDP_PORT_RANGE_START;
2678 : }
2679 :
2680 : static void
2681 216 : vr_flow_update_link_local_port(struct vrouter *router, vr_flow_req *req,
2682 : struct vr_flow_entry *fe)
2683 : {
2684 216 : bool set_port = false;
2685 216 : int port = 0;
2686 :
2687 216 : if (!req || !fe)
2688 0 : return;
2689 :
2690 216 : if (fe->fe_type != VP_TYPE_IP)
2691 10 : return;
2692 :
2693 206 : if (fe->fe_key.flow_proto == VR_IP_PROTO_ICMP) {
2694 : /*
2695 : * ICMP id passed as source port would be
2696 : * used for relaxed policy flow lookup
2697 : */
2698 173 : port = ntohs(fe->fe_key.flow_sport);
2699 : } else {
2700 33 : port = ntohs(fe->fe_key.flow_dport);
2701 : }
2702 :
2703 206 : if (req->fr_flags & VR_FLOW_FLAG_LINK_LOCAL) {
2704 4 : if (!(fe->fe_flags & VR_FLOW_FLAG_LINK_LOCAL))
2705 2 : set_port = true;
2706 202 : } else if (fe->fe_flags & VR_FLOW_FLAG_LINK_LOCAL) {
2707 0 : vr_clear_link_local_port(router, AF_INET, fe->fe_key.flow_proto,
2708 : port);
2709 : }
2710 :
2711 206 : if (req->fr_flags & VR_FLOW_BGP_SERVICE) {
2712 0 : if (!(fe->fe_flags & VR_FLOW_BGP_SERVICE))
2713 0 : set_port = true;
2714 : }
2715 :
2716 206 : if (set_port) {
2717 2 : vr_set_link_local_port(router, AF_INET, fe->fe_key.flow_proto, port);
2718 : }
2719 :
2720 206 : return;
2721 : }
2722 :
2723 : static int
2724 0 : vr_flow_force_evict (struct vrouter *router, vr_flow_req *req)
2725 : {
2726 0 : struct vr_flow_entry *fe = NULL;
2727 :
2728 0 : fe = vr_flow_get_entry(router, req->fr_index);
2729 0 : if (fe) {
2730 : /* Do force eviction only for TCP flows with dead flag set */
2731 0 : if (fe->fe_key.flow_proto != VR_IP_PROTO_TCP) {
2732 0 : return -EINVAL;
2733 : }
2734 0 : if (!(fe->fe_tcp_flags & VR_FLOW_TCP_DEAD)) {
2735 0 : return -EINVAL;
2736 : }
2737 0 : if (!(fe->fe_flags & VR_FLOW_FLAG_ACTIVE)) {
2738 0 : return -EINVAL;
2739 : }
2740 : /*
2741 : * We have a TCP flow which is dead,
2742 : * Evict Candidate may or may not be set
2743 : */
2744 0 : vr_flow_start_modify(router, fe);
2745 : /*
2746 : * Reset flow's reverse flow index as we don't want to
2747 : * touch reverse flow
2748 : */
2749 0 : fe->fe_flags &= ~VR_RFLOW_VALID;
2750 0 : fe->fe_rflow = -1;
2751 0 : if (!(fe->fe_flags & VR_FLOW_FLAG_EVICT_CANDIDATE)) {
2752 0 : __vr_flow_mark_evict(router, fe);
2753 : }
2754 0 : __vr_flow_schedule_transition(router, fe, req->fr_index, fe->fe_flags);
2755 : } else {
2756 0 : return -EINVAL;
2757 : }
2758 0 : return 0;
2759 : }
2760 :
2761 :
2762 : /* command from agent */
2763 : static int
2764 322 : vr_flow_set(struct vrouter *router, vr_flow_req *req,
2765 : vr_flow_response *flow_resp)
2766 0 : {
2767 : int ret;
2768 : int8_t cur_fe_underlay_ecmp_index;
2769 322 : unsigned int fe_index = (unsigned int)-1;
2770 322 : uint8_t fe_gen_id = 0;
2771 322 : bool new_flow = false, modified = false;
2772 :
2773 322 : struct vr_flow_entry *fe = NULL, *rfe = NULL;
2774 322 : struct vr_flow_table_info *infop = router->vr_flow_table_info;
2775 :
2776 322 : router = vrouter_get(req->fr_rid);
2777 322 : if (!router)
2778 0 : return -EINVAL;
2779 :
2780 322 : flow_resp->fresp_index = req->fr_index;
2781 :
2782 322 : if (req->fr_extflags & VR_FLOW_EXT_FLAG_FORCE_EVICT) {
2783 0 : return vr_flow_force_evict(router, req);
2784 : }
2785 :
2786 322 : fe = vr_flow_get_entry(router, req->fr_index);
2787 322 : if (fe) {
2788 210 : if (!(modified = vr_flow_start_modify(router, fe)))
2789 0 : return -EBUSY;
2790 210 : fe_index = (unsigned int)(req->fr_index);
2791 : }
2792 :
2793 322 : if ((ret = vr_flow_set_req_is_invalid(router, req, fe)))
2794 0 : goto exit_set;
2795 :
2796 322 : if (fe) {
2797 210 : if ((fe->fe_action == VR_FLOW_ACTION_HOLD) &&
2798 2 : ((req->fr_action != fe->fe_action) ||
2799 0 : !(req->fr_flags & VR_FLOW_FLAG_ACTIVE))) {
2800 2 : vr_sync_fetch_and_add_64u(&infop->vfti_action_count, 1);
2801 : } else {
2802 208 : infop->vfti_changed++;
2803 : }
2804 :
2805 : }
2806 : /*
2807 : * for delete, absence of the requested flow entry is caustic. so
2808 : * handle that case first
2809 : */
2810 322 : if (!(req->fr_flags & VR_FLOW_FLAG_ACTIVE)) {
2811 106 : if (!fe)
2812 8 : return -ENOENT;
2813 :
2814 98 : infop->vfti_deleted++;
2815 98 : flow_resp->fresp_flags |= VR_FLOW_RESP_FLAG_DELETED;
2816 98 : return vr_flow_delete(router, req, fe);
2817 : }
2818 :
2819 :
2820 : /*
2821 : * for non-delete cases, absence of flow entry means addition of a
2822 : * new flow entry with the key specified in the request
2823 : */
2824 216 : if (!fe) {
2825 104 : fe = vr_add_flow_req(req, &fe_index, &fe_gen_id);
2826 104 : if (!fe) {
2827 0 : if (fe_index != (unsigned int)-1) {
2828 : /*
2829 : * add flow req failed to allocate an entry due to race
2830 : * between agent and datapath, where flow entry at fe_index
2831 : * was already created due to packet trap, return EEXIST
2832 : * error and allow agent to wait and handle flow add due to
2833 : * packet trap
2834 : */
2835 0 : flow_resp->fresp_index = fe_index;
2836 0 : flow_resp->fresp_gen_id = fe_gen_id;
2837 0 : return -EEXIST;
2838 : }
2839 0 : return -ENOSPC;
2840 : }
2841 :
2842 104 : new_flow = true;
2843 104 : infop->vfti_added++;
2844 : } else {
2845 112 : if ((req->fr_action == VR_FLOW_ACTION_HOLD) &&
2846 0 : (fe->fe_action != req->fr_action)) {
2847 0 : if (!fe->fe_hold_list) {
2848 0 : fe->fe_hold_list = vr_zalloc(sizeof(struct vr_flow_queue),
2849 : VR_FLOW_QUEUE_OBJECT);
2850 0 : if (!fe->fe_hold_list) {
2851 0 : ret = -ENOMEM;
2852 0 : goto exit_set;
2853 : }
2854 : }
2855 : }
2856 : }
2857 :
2858 216 : flow_resp->fresp_gen_id = fe->fe_gen_id;
2859 216 : flow_resp->fresp_index = fe->fe_hentry.hentry_index;
2860 :
2861 216 : vr_flow_set_mirror(router, req, fe);
2862 :
2863 216 : if (req->fr_flags & VR_RFLOW_VALID) {
2864 160 : fe->fe_rflow = req->fr_rindex;
2865 : } else {
2866 56 : if (fe->fe_rflow >= 0)
2867 0 : fe->fe_rflow = -1;
2868 : }
2869 :
2870 216 : fe->fe_vrf = req->fr_flow_vrf;
2871 216 : if (req->fr_flags & VR_FLOW_FLAG_VRFT)
2872 12 : fe->fe_dvrf = req->fr_flow_dvrf;
2873 :
2874 216 : vr_flow_update_link_local_port(router, req, fe);
2875 :
2876 216 : if (fe->fe_ecmp_nh_index == -1)
2877 216 : (void)vr_sync_bool_compare_and_swap_8s(&fe->fe_ecmp_nh_index, -1,
2878 : req->fr_ecmp_nh_index);
2879 :
2880 216 : fe->fe_src_nh_index = req->fr_src_nh_index;
2881 216 : fe->fe_qos_id = req->fr_qos_id;
2882 :
2883 216 : if ((req->fr_action == VR_FLOW_ACTION_HOLD) &&
2884 0 : (fe->fe_action != VR_FLOW_ACTION_HOLD)) {
2885 0 : vr_flow_entry_set_hold(router, fe, false);
2886 : } else {
2887 216 : fe->fe_action = req->fr_action;
2888 : }
2889 :
2890 216 : fe->fe_ttl = req->fr_ttl;
2891 :
2892 216 : cur_fe_underlay_ecmp_index = req->fr_underlay_ecmp_index;
2893 : /* repeats until the comapre and swap operation is successful */
2894 216 : while(!vr_sync_bool_compare_and_swap_8s(&fe->fe_underlay_ecmp_index,
2895 : fe->fe_underlay_ecmp_index, cur_fe_underlay_ecmp_index)) {
2896 0 : continue;
2897 : }
2898 :
2899 216 : if (fe->fe_action == VR_FLOW_ACTION_DROP)
2900 0 : fe->fe_drop_reason = (uint8_t)req->fr_drop_reason;
2901 :
2902 216 : fe->fe_flags = VR_FLOW_FLAG_DP_BITS(fe) |
2903 216 : VR_FLOW_FLAG_MASK(req->fr_flags);
2904 216 : fe->fe_flags1 = req->fr_flags1;
2905 216 : if (new_flow) {
2906 :
2907 104 : flow_resp->fresp_bytes = fe->fe_stats.flow_bytes;
2908 104 : flow_resp->fresp_packets = fe->fe_stats.flow_packets;
2909 104 : flow_resp->fresp_stats_oflow = (fe->fe_stats.flow_bytes_oflow |
2910 104 : (fe->fe_stats.flow_packets_oflow << 16));
2911 :
2912 104 : if (fe->fe_flags & VR_FLOW_FLAG_NEW_FLOW) {
2913 104 : if (fe->fe_stats.flow_packets || fe->fe_stats.flow_packets_oflow)
2914 0 : memset(&fe->fe_stats, 0, sizeof(fe->fe_stats));
2915 : }
2916 :
2917 104 : if (fe->fe_flags & VR_RFLOW_VALID) {
2918 49 : rfe = vr_flow_get_entry(router, fe->fe_rflow);
2919 49 : if (rfe) {
2920 49 : vr_flow_tcp_rflow_set(router, fe, rfe);
2921 : }
2922 : }
2923 :
2924 : }
2925 :
2926 216 : vr_flow_udp_src_port(router, fe);
2927 :
2928 : /* Mock Src UDP port used for vrouter simulation - vtest */
2929 216 : if(req->fr_extflags & VR_FLOW_EXT_FLAG_MOCK_SRC_UDP)
2930 2 : fe->fe_udp_src_port = VR_FLOW_MOCK_SRC_UDP_PORT;
2931 :
2932 216 : if (fe->fe_flags & VR_FLOW_FLAG_NEW_FLOW)
2933 104 : fe->fe_flags &= ~VR_FLOW_FLAG_NEW_FLOW;
2934 :
2935 :
2936 :
2937 216 : ret = vr_flow_schedule_transition(router, req, fe);
2938 :
2939 : /*
2940 : * offload, no need to differentiate between add and modify. Pass the
2941 : * reverse flow as well if present.
2942 : */
2943 216 : if (!ret) {
2944 216 : vr_offload_flow_set(fe, fe_index, rfe);
2945 : }
2946 :
2947 0 : exit_set:
2948 216 : if (modified && fe) {
2949 112 : vr_flow_stop_modify(router, fe);
2950 : }
2951 :
2952 216 : return ret;
2953 : }
2954 :
2955 : static void
2956 13 : vr_flow_table_data_destroy(vr_flow_table_data *ftable)
2957 : {
2958 13 : if (!ftable)
2959 0 : return;
2960 :
2961 13 : if (ftable->ftable_file_path) {
2962 13 : vr_free(ftable->ftable_file_path, VR_FLOW_REQ_PATH_OBJECT);
2963 13 : ftable->ftable_file_path = NULL;
2964 : }
2965 :
2966 13 : if (ftable->ftable_hold_stat && ftable->ftable_hold_stat_size) {
2967 13 : vr_free(ftable->ftable_hold_stat, VR_FLOW_HOLD_STAT_OBJECT);
2968 13 : ftable->ftable_hold_stat = NULL;
2969 13 : ftable->ftable_hold_stat_size = 0;
2970 : }
2971 :
2972 13 : vr_free(ftable, VR_FLOW_TABLE_DATA_OBJECT);
2973 :
2974 13 : return;
2975 : }
2976 :
2977 : static vr_flow_table_data *
2978 13 : vr_flow_table_data_get(vr_flow_table_data *ref)
2979 : {
2980 : unsigned int hold_stat_size;
2981 13 : unsigned int num_cpus = vr_num_cpus;
2982 13 : vr_flow_table_data *ftable = vr_zalloc(sizeof(*ref),
2983 : VR_FLOW_TABLE_DATA_OBJECT);
2984 :
2985 13 : if (!ftable)
2986 0 : return NULL;
2987 :
2988 13 : if (vr_flow_path) {
2989 13 : ftable->ftable_file_path = vr_zalloc(VR_UNIX_PATH_MAX,
2990 : VR_FLOW_REQ_PATH_OBJECT);
2991 13 : if (!ftable->ftable_file_path) {
2992 0 : vr_free(ftable, VR_FLOW_TABLE_DATA_OBJECT);
2993 0 : return NULL;
2994 : }
2995 : }
2996 :
2997 13 : if (num_cpus > VR_FLOW_MAX_CPUS)
2998 0 : num_cpus = VR_FLOW_MAX_CPUS;
2999 :
3000 13 : hold_stat_size = num_cpus * sizeof(uint32_t);
3001 13 : ftable->ftable_hold_stat = vr_zalloc(hold_stat_size, VR_FLOW_HOLD_STAT_OBJECT);
3002 13 : if (!ftable->ftable_hold_stat) {
3003 0 : if (ftable->ftable_file_path) {
3004 0 : vr_free(ftable->ftable_file_path, VR_FLOW_REQ_PATH_OBJECT);
3005 0 : ftable->ftable_file_path = NULL;
3006 : }
3007 :
3008 0 : vr_free(ftable, VR_FLOW_TABLE_DATA_OBJECT);
3009 0 : return NULL;
3010 : }
3011 13 : ftable->ftable_hold_stat_size = num_cpus;
3012 :
3013 13 : return ftable;
3014 : }
3015 :
3016 : void
3017 8186880 : update_flow_entry(vr_htable_t table __attribute__unused__, vr_hentry_t *ent ,
3018 : unsigned int index, void *data __attribute__unused__)
3019 : {
3020 8186880 : struct vr_flow_entry *fe = (struct vr_flow_entry *)ent;
3021 :
3022 8186880 : if (fe == NULL)
3023 8186865 : return;
3024 :
3025 15 : vr_offload_flow_stats_update(fe);
3026 : }
3027 :
3028 : /*
3029 : * sandesh handler for vr_flow_table_data
3030 : */
3031 : void
3032 13 : vr_flow_table_data_process(void *s_req)
3033 : {
3034 13 : int i, ret = 0;
3035 13 : uint64_t hold_count = 0;
3036 : struct vrouter *router;
3037 : struct vr_flow_table_info *infop;
3038 13 : vr_flow_table_data *resp = NULL, *ftable = (vr_flow_table_data *)s_req;
3039 :
3040 13 : if (!ftable) {
3041 0 : ret = -ENOMEM;
3042 0 : goto send_response;
3043 : }
3044 13 : router = vrouter_get(ftable->ftable_rid);
3045 13 : if (! router) {
3046 0 : ret = -ENOMEM;
3047 0 : goto send_response;
3048 : }
3049 :
3050 13 : if(EINVAL == vr_htable_trav(router->vr_flow_table, 0, update_flow_entry, NULL))
3051 : {
3052 0 : ret = -ENOMEM;
3053 0 : goto send_response;
3054 : }
3055 13 : resp = vr_flow_table_data_get(ftable);
3056 13 : if (!resp) {
3057 0 : ret = -ENOMEM;
3058 0 : goto send_response;
3059 : }
3060 :
3061 13 : infop = router->vr_flow_table_info;
3062 13 : resp->ftable_op = ftable->ftable_op;
3063 13 : resp->ftable_size = vr_flow_table_size(router);
3064 : #if defined(__linux__) && defined(__KERNEL__)
3065 : resp->ftable_dev = vr_flow_major;
3066 : #endif
3067 13 : if (vr_flow_path) {
3068 13 : strncpy(resp->ftable_file_path, vr_flow_path, VR_UNIX_PATH_MAX - 1);
3069 : }
3070 :
3071 13 : if (!infop)
3072 0 : goto send_response;
3073 :
3074 13 : resp->ftable_used_entries = vr_flow_table_used_total_entries(router);
3075 13 : resp->ftable_deleted = infop->vfti_deleted;
3076 13 : resp->ftable_changed = infop->vfti_changed;
3077 13 : resp->ftable_processed = infop->vfti_action_count;
3078 13 : resp->ftable_hold_oflows = infop->vfti_oflows;
3079 13 : resp->ftable_added = infop->vfti_added;
3080 13 : resp->ftable_cpus = vr_num_cpus;
3081 : /* we only have space for 64 stats block max when encoding */
3082 169 : for (i = 0; ((i < vr_num_cpus) && (i < VR_FLOW_MAX_CPUS)); i++) {
3083 156 : resp->ftable_hold_stat[i] = infop->vfti_hold_count[i];
3084 156 : hold_count += resp->ftable_hold_stat[i];
3085 : }
3086 :
3087 13 : resp->ftable_created = hold_count;
3088 13 : resp->ftable_oflow_entries = vr_flow_table_used_oflow_entries(router);
3089 13 : resp->ftable_burst_free_tokens = infop->vfti_burst_tokens - infop->vfti_burst_used;
3090 13 : resp->ftable_hold_entries = vr_flow_table_hold_count(router);
3091 :
3092 13 : send_response:
3093 13 : vr_message_response(VR_FLOW_TABLE_DATA_OBJECT_ID, resp, ret, false);
3094 13 : if (resp)
3095 13 : vr_flow_table_data_destroy(resp);
3096 :
3097 13 : return;
3098 : }
3099 :
3100 : /*
3101 : * sandesh handler for vr_flow_req
3102 : */
3103 : void
3104 322 : vr_flow_req_process(void *s_req)
3105 : {
3106 322 : int ret = 0;
3107 : struct vrouter *router;
3108 322 : vr_flow_req *req = (vr_flow_req *)s_req;
3109 : vr_flow_response flow_resp;
3110 :
3111 322 : router = vrouter_get(req->fr_rid);
3112 322 : switch (req->fr_op) {
3113 322 : case FLOW_OP_FLOW_SET:
3114 :
3115 322 : flow_resp.fresp_rid = 0;
3116 322 : flow_resp.fresp_op = req->fr_op;
3117 :
3118 322 : ret = vr_flow_set(router, req, &flow_resp);
3119 322 : break;
3120 :
3121 0 : default:
3122 0 : ret = -EINVAL;
3123 : }
3124 :
3125 322 : vr_message_response(VR_FLOW_RESPONSE_OBJECT_ID, &flow_resp, ret, false);
3126 :
3127 322 : return;
3128 : }
3129 :
3130 : void
3131 0 : vr_flow_response_process(void *s_req)
3132 : {
3133 0 : return;
3134 : }
3135 :
3136 : static void
3137 53 : vr_flow_table_info_destroy(struct vrouter *router)
3138 : {
3139 53 : if (!router->vr_flow_table_info)
3140 0 : return;
3141 :
3142 53 : vr_free(router->vr_flow_table_info, VR_FLOW_TABLE_INFO_OBJECT);
3143 53 : router->vr_flow_table_info = NULL;
3144 53 : router->vr_flow_table_info_size = 0;
3145 :
3146 53 : return;
3147 : }
3148 :
3149 : static void
3150 53 : vr_flow_table_info_reset(struct vrouter *router)
3151 : {
3152 53 : if (!router->vr_flow_table_info)
3153 0 : return;
3154 :
3155 53 : if (router->vr_flow_table_info->vfti_timer) {
3156 0 : vr_delete_timer(router->vr_flow_table_info->vfti_timer);
3157 0 : vr_free(router->vr_flow_table_info->vfti_timer, VR_TIMER_OBJECT);
3158 0 : router->vr_flow_table_info->vfti_timer = NULL;
3159 : }
3160 :
3161 53 : memset(router->vr_flow_table_info, 0, router->vr_flow_table_info_size);
3162 :
3163 53 : return;
3164 : }
3165 :
3166 : static int
3167 53 : vr_flow_table_info_init(struct vrouter *router)
3168 : {
3169 : unsigned int size;
3170 : struct vr_flow_table_info *infop;
3171 :
3172 53 : if (router->vr_flow_table_info)
3173 0 : return 0;
3174 :
3175 53 : size = sizeof(struct vr_flow_table_info) + sizeof(uint32_t) * vr_num_cpus;
3176 53 : infop = (struct vr_flow_table_info *)vr_zalloc(size,
3177 : VR_FLOW_TABLE_INFO_OBJECT);
3178 53 : if (!infop)
3179 0 : return vr_module_error(-ENOMEM, __FUNCTION__, __LINE__, size);
3180 :
3181 53 : router->vr_flow_table_info = infop;
3182 53 : router->vr_flow_table_info_size = size;
3183 :
3184 53 : return 0;
3185 : }
3186 :
3187 : static void
3188 53 : vr_flow_table_destroy(struct vrouter *router)
3189 : {
3190 53 : if (router->vr_flow_table) {
3191 53 : vr_htable_delete(router->vr_flow_table);
3192 53 : router->vr_flow_table = NULL;
3193 : }
3194 :
3195 53 : vr_flow_table_info_destroy(router);
3196 :
3197 53 : return;
3198 : }
3199 :
3200 : static void
3201 33377280 : vr_flow_invalidate_entry(vr_htable_t htable, vr_hentry_t *ent,
3202 : unsigned int index, void *data)
3203 : {
3204 : struct vr_flow_entry *fe;
3205 : struct vr_forwarding_md fmd;
3206 : struct vr_flow_md flmd;
3207 33377280 : struct vrouter *router = (struct vrouter *)data;
3208 :
3209 33377280 : if (!ent || !data)
3210 33377269 : return;
3211 :
3212 33377280 : fe = CONTAINER_OF(fe_hentry, struct vr_flow_entry, ent);
3213 33377280 : if (!(fe->fe_flags & VR_FLOW_FLAG_ACTIVE))
3214 33377269 : return;
3215 :
3216 11 : flmd.flmd_defer_data = NULL;
3217 11 : flmd.flmd_index = index;
3218 11 : flmd.flmd_flags = fe->fe_flags;
3219 :
3220 11 : vr_init_forwarding_md(&fmd);
3221 :
3222 11 : fe->fe_action = VR_FLOW_ACTION_DROP;
3223 11 : vr_flush_entry(router, fe, &flmd, &fmd);
3224 11 : vr_flow_reset_entry(router, fe);
3225 : }
3226 :
3227 : static void
3228 53 : vr_flow_table_reset(struct vrouter *router)
3229 : {
3230 53 : vr_htable_reset(router->vr_flow_table,
3231 : vr_flow_invalidate_entry, router);
3232 53 : vr_flow_table_info_reset(router);
3233 :
3234 53 : return;
3235 : }
3236 :
3237 : void
3238 66 : vr_compute_size_oflow_table(void)
3239 : {
3240 : /*
3241 : * Overflow entries is 20% of the main flow table
3242 : * adjusted to next 1k
3243 : */
3244 66 : if (!vr_oflow_entries) {
3245 0 : vr_oflow_entries = ((vr_flow_entries / 5) + 1023) & ~1023;
3246 : }
3247 66 : }
3248 :
3249 : static int
3250 53 : vr_flow_table_init(struct vrouter *router)
3251 : {
3252 53 : if (!router->vr_flow_table) {
3253 :
3254 53 : vr_compute_size_oflow_table();
3255 :
3256 53 : if (!vr_flow_table && vr_huge_page_mem_get) {
3257 :
3258 0 : vr_flow_table = vr_huge_page_mem_get(VR_FLOW_TABLE_SIZE +
3259 : VR_OFLOW_TABLE_SIZE, &vr_flow_path);
3260 0 : if (vr_flow_table)
3261 0 : vr_oflow_table = (char*)vr_flow_table + VR_FLOW_TABLE_SIZE;
3262 : }
3263 :
3264 53 : router->vr_flow_table = vr_htable_attach(router, vr_flow_entries,
3265 : vr_flow_table, vr_oflow_entries, vr_oflow_table,
3266 : sizeof(struct vr_flow_entry), 0, 0, vr_flow_get_key);
3267 :
3268 53 : if (!router->vr_flow_table) {
3269 0 : return vr_module_error(-ENOMEM, __FUNCTION__,
3270 0 : __LINE__, vr_flow_entries + vr_oflow_entries);
3271 : }
3272 : }
3273 :
3274 53 : return vr_flow_table_info_init(router);
3275 : }
3276 :
3277 : static void
3278 53 : vr_link_local_ports_reset(struct vrouter *router)
3279 : {
3280 53 : if (router->vr_link_local_ports) {
3281 53 : memset(router->vr_link_local_ports,
3282 53 : 0, router->vr_link_local_ports_size);
3283 : }
3284 :
3285 53 : return;
3286 : }
3287 :
3288 : static void
3289 53 : vr_link_local_ports_exit(struct vrouter *router)
3290 : {
3291 53 : if (router->vr_link_local_ports) {
3292 53 : vr_free(router->vr_link_local_ports, VR_FLOW_LINK_LOCAL_OBJECT);
3293 53 : router->vr_link_local_ports = NULL;
3294 53 : router->vr_link_local_ports_size = 0;
3295 : }
3296 :
3297 53 : return;
3298 : }
3299 :
3300 : static int
3301 53 : vr_link_local_ports_init(struct vrouter *router)
3302 : {
3303 : unsigned int port_range, bytes;
3304 :
3305 53 : if (router->vr_link_local_ports)
3306 0 : return 0;
3307 :
3308 : /* ICMP, Udp and TCP inclusive of low and high limits*/
3309 53 : port_range = VR_LL_RP_MAX *
3310 : ((VR_DYNAMIC_PORT_END - VR_DYNAMIC_PORT_START) + 1);
3311 : /* Make it 16 bit boundary */
3312 53 : bytes = (port_range + 15) & ~15;
3313 : /* Bits to Bytes */
3314 53 : bytes /= 8;
3315 :
3316 53 : router->vr_link_local_ports = vr_zalloc(bytes, VR_FLOW_LINK_LOCAL_OBJECT);
3317 53 : if (!router->vr_link_local_ports)
3318 0 : return -1;
3319 53 : router->vr_link_local_ports_size = bytes;
3320 :
3321 53 : return 0;
3322 : }
3323 :
3324 : /* flow module exit and init */
3325 : void
3326 53 : vr_flow_exit(struct vrouter *router, bool soft_reset)
3327 : {
3328 53 : vr_flow_table_reset(router);
3329 53 : vr_link_local_ports_reset(router);
3330 53 : if (!soft_reset) {
3331 53 : vr_flow_table_destroy(router);
3332 53 : vr_fragment_table_exit(router);
3333 53 : vr_link_local_ports_exit(router);
3334 : }
3335 :
3336 53 : return;
3337 : }
3338 :
3339 : int
3340 53 : vr_flow_mem(struct vrouter *router)
3341 : {
3342 : int ret;
3343 :
3344 53 : if ((ret = vr_fragment_table_init(router)) < 0)
3345 0 : return ret;
3346 :
3347 53 : if ((ret = vr_flow_table_init(router)))
3348 0 : return ret;
3349 :
3350 53 : if ((ret = vr_link_local_ports_init(router)))
3351 0 : return ret;
3352 :
3353 53 : return 0;
3354 : }
3355 :
3356 : int
3357 53 : vr_flow_init(struct vrouter *router)
3358 : {
3359 53 : return 0;
3360 : }
3361 :
3362 : /*
3363 : * Called by offload module to update flow stats with packets which have been
3364 : * offloaded. over_flow_bytes and over_flow_packets account for overflows which
3365 : * happen in firmware between updates using this function.
3366 : */
3367 : int
3368 0 : vr_flow_incr_stats(int fe_index, uint32_t flow_bytes, uint16_t over_flow_bytes,
3369 : uint32_t flow_packets, uint8_t over_flow_packets)
3370 : {
3371 0 : struct vrouter *router = vrouter_get(0);
3372 : struct vr_flow_entry *fe;
3373 : uint32_t new_stats;
3374 :
3375 0 : if (router == NULL)
3376 0 : return -EINVAL;
3377 :
3378 0 : fe = vr_flow_get_entry(router, fe_index);
3379 0 : if (fe == NULL)
3380 0 : return -ENOENT;
3381 :
3382 0 : if (!(fe->fe_flags & VR_FLOW_FLAG_ACTIVE))
3383 0 : return -ENOENT;
3384 :
3385 0 : new_stats = vr_sync_add_and_fetch_32u(&fe->fe_stats.flow_bytes, flow_bytes);
3386 0 : if (new_stats < flow_bytes)
3387 0 : ++fe->fe_stats.flow_bytes_oflow;
3388 0 : fe->fe_stats.flow_bytes_oflow += over_flow_bytes;
3389 :
3390 0 : new_stats = vr_sync_add_and_fetch_32u(&fe->fe_stats.flow_packets,
3391 : flow_packets);
3392 0 : if (new_stats < flow_packets)
3393 0 : ++fe->fe_stats.flow_packets_oflow;
3394 0 : fe->fe_stats.flow_packets_oflow += over_flow_packets;
3395 :
3396 0 : return 0;
3397 : }
|