00832635a5a75651c10fd3cd78ab7d6318fa3c3d
[vpp.git] / vnet / vnet / handoff.h
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #ifndef included_vnet_handoff_h
17 #define included_vnet_handoff_h
18
19 #include <vlib/vlib.h>
20 #include <vnet/ethernet/ethernet.h>
21 #include <vnet/ip/ip4_packet.h>
22 #include <vnet/ip/ip6_packet.h>
23 #include <vnet/mpls-gre/packet.h>
24
25 typedef enum
26 {
27   HANDOFF_DISPATCH_NEXT_IP4_INPUT,
28   HANDOFF_DISPATCH_NEXT_IP6_INPUT,
29   HANDOFF_DISPATCH_NEXT_MPLS_INPUT,
30   HANDOFF_DISPATCH_NEXT_ETHERNET_INPUT,
31   HANDOFF_DISPATCH_NEXT_DROP,
32   HANDOFF_DISPATCH_N_NEXT,
33 } handoff_dispatch_next_t;
34
35 static inline void
36 vlib_put_handoff_queue_elt (vlib_frame_queue_elt_t * hf)
37 {
38   CLIB_MEMORY_BARRIER ();
39   hf->valid = 1;
40 }
41
42 static inline vlib_frame_queue_elt_t *
43 vlib_get_handoff_queue_elt (u32 vlib_worker_index)
44 {
45   vlib_frame_queue_t *fq;
46   vlib_frame_queue_elt_t *elt;
47   u64 new_tail;
48
49   fq = vlib_frame_queues[vlib_worker_index];
50   ASSERT (fq);
51
52   new_tail = __sync_add_and_fetch (&fq->tail, 1);
53
54   /* Wait until a ring slot is available */
55   while (new_tail >= fq->head_hint + fq->nelts)
56     vlib_worker_thread_barrier_check ();
57
58   elt = fq->elts + (new_tail & (fq->nelts - 1));
59
60   /* this would be very bad... */
61   while (elt->valid)
62     ;
63
64   elt->msg_type = VLIB_FRAME_QUEUE_ELT_DISPATCH_FRAME;
65   elt->last_n_vectors = elt->n_vectors = 0;
66
67   return elt;
68 }
69
70 static inline vlib_frame_queue_t *
71 is_vlib_handoff_queue_congested (u32 vlib_worker_index,
72                                  u32 queue_hi_thresh,
73                                  vlib_frame_queue_t **
74                                  handoff_queue_by_worker_index)
75 {
76   vlib_frame_queue_t *fq;
77
78   fq = handoff_queue_by_worker_index[vlib_worker_index];
79   if (fq != (vlib_frame_queue_t *) (~0))
80     return fq;
81
82   fq = vlib_frame_queues[vlib_worker_index];
83   ASSERT (fq);
84
85   if (PREDICT_FALSE (fq->tail >= (fq->head_hint + queue_hi_thresh)))
86     {
87       /* a valid entry in the array will indicate the queue has reached
88        * the specified threshold and is congested
89        */
90       handoff_queue_by_worker_index[vlib_worker_index] = fq;
91       fq->enqueue_full_events++;
92       return fq;
93     }
94
95   return NULL;
96 }
97
98 static inline vlib_frame_queue_elt_t *
99 dpdk_get_handoff_queue_elt (u32 vlib_worker_index,
100                             vlib_frame_queue_elt_t **
101                             handoff_queue_elt_by_worker_index)
102 {
103   vlib_frame_queue_elt_t *elt;
104
105   if (handoff_queue_elt_by_worker_index[vlib_worker_index])
106     return handoff_queue_elt_by_worker_index[vlib_worker_index];
107
108   elt = vlib_get_handoff_queue_elt (vlib_worker_index);
109
110   handoff_queue_elt_by_worker_index[vlib_worker_index] = elt;
111
112   return elt;
113 }
114
115 static inline u64
116 ipv4_get_key (ip4_header_t * ip)
117 {
118   u64 hash_key;
119
120   hash_key = *((u64 *) (&ip->address_pair)) ^ ip->protocol;
121
122   return hash_key;
123 }
124
125 static inline u64
126 ipv6_get_key (ip6_header_t * ip)
127 {
128   u64 hash_key;
129
130   hash_key = ip->src_address.as_u64[0] ^
131     rotate_left (ip->src_address.as_u64[1], 13) ^
132     rotate_left (ip->dst_address.as_u64[0], 26) ^
133     rotate_left (ip->dst_address.as_u64[1], 39) ^ ip->protocol;
134
135   return hash_key;
136 }
137
138 #define MPLS_BOTTOM_OF_STACK_BIT_MASK   0x00000100U
139 #define MPLS_LABEL_MASK                 0xFFFFF000U
140
141 static inline u64
142 mpls_get_key (mpls_unicast_header_t * m)
143 {
144   u64 hash_key;
145   u8 ip_ver;
146
147
148   /* find the bottom of the MPLS label stack. */
149   if (PREDICT_TRUE (m->label_exp_s_ttl &
150                     clib_net_to_host_u32 (MPLS_BOTTOM_OF_STACK_BIT_MASK)))
151     {
152       goto bottom_lbl_found;
153     }
154   m++;
155
156   if (PREDICT_TRUE (m->label_exp_s_ttl &
157                     clib_net_to_host_u32 (MPLS_BOTTOM_OF_STACK_BIT_MASK)))
158     {
159       goto bottom_lbl_found;
160     }
161   m++;
162
163   if (m->label_exp_s_ttl &
164       clib_net_to_host_u32 (MPLS_BOTTOM_OF_STACK_BIT_MASK))
165     {
166       goto bottom_lbl_found;
167     }
168   m++;
169
170   if (m->label_exp_s_ttl &
171       clib_net_to_host_u32 (MPLS_BOTTOM_OF_STACK_BIT_MASK))
172     {
173       goto bottom_lbl_found;
174     }
175   m++;
176
177   if (m->label_exp_s_ttl &
178       clib_net_to_host_u32 (MPLS_BOTTOM_OF_STACK_BIT_MASK))
179     {
180       goto bottom_lbl_found;
181     }
182
183   /* the bottom label was not found - use the last label */
184   hash_key = m->label_exp_s_ttl & clib_net_to_host_u32 (MPLS_LABEL_MASK);
185
186   return hash_key;
187
188 bottom_lbl_found:
189   m++;
190   ip_ver = (*((u8 *) m) >> 4);
191
192   /* find out if it is IPV4 or IPV6 header */
193   if (PREDICT_TRUE (ip_ver == 4))
194     {
195       hash_key = ipv4_get_key ((ip4_header_t *) m);
196     }
197   else if (PREDICT_TRUE (ip_ver == 6))
198     {
199       hash_key = ipv6_get_key ((ip6_header_t *) m);
200     }
201   else
202     {
203       /* use the bottom label */
204       hash_key =
205         (m - 1)->label_exp_s_ttl & clib_net_to_host_u32 (MPLS_LABEL_MASK);
206     }
207
208   return hash_key;
209
210 }
211
212
213 static inline u64
214 eth_get_key (ethernet_header_t * h0)
215 {
216   u64 hash_key;
217
218   if (PREDICT_TRUE (h0->type) == clib_host_to_net_u16 (ETHERNET_TYPE_IP4))
219     {
220       hash_key = ipv4_get_key ((ip4_header_t *) (h0 + 1));
221     }
222   else if (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_IP6))
223     {
224       hash_key = ipv6_get_key ((ip6_header_t *) (h0 + 1));
225     }
226   else if (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_MPLS_UNICAST))
227     {
228       hash_key = mpls_get_key ((mpls_unicast_header_t *) (h0 + 1));
229     }
230   else if ((h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_VLAN)) ||
231            (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD)))
232     {
233       ethernet_vlan_header_t *outer = (ethernet_vlan_header_t *) (h0 + 1);
234
235       outer = (outer->type == clib_host_to_net_u16 (ETHERNET_TYPE_VLAN)) ?
236         outer + 1 : outer;
237       if (PREDICT_TRUE (outer->type) ==
238           clib_host_to_net_u16 (ETHERNET_TYPE_IP4))
239         {
240           hash_key = ipv4_get_key ((ip4_header_t *) (outer + 1));
241         }
242       else if (outer->type == clib_host_to_net_u16 (ETHERNET_TYPE_IP6))
243         {
244           hash_key = ipv6_get_key ((ip6_header_t *) (outer + 1));
245         }
246       else if (outer->type ==
247                clib_host_to_net_u16 (ETHERNET_TYPE_MPLS_UNICAST))
248         {
249           hash_key = mpls_get_key ((mpls_unicast_header_t *) (outer + 1));
250         }
251       else
252         {
253           hash_key = outer->type;
254         }
255     }
256   else
257     {
258       hash_key = 0;
259     }
260
261   return hash_key;
262 }
263
264 #endif /* included_vnet_handoff_h */
265
266 /*
267  * fd.io coding-style-patch-verification: ON
268  *
269  * Local Variables:
270  * eval: (c-set-style "gnu")
271  * End:
272  */