2 * Copyright (c) 2020 VMware, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 #include "conntrack-private.h"
21 #include "conntrack-tp.h"
23 #include "openvswitch/vlog.h"
25 VLOG_DEFINE_THIS_MODULE(conntrack_tp
);
26 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
28 static const char *ct_timeout_str
[] = {
29 #define CT_TIMEOUT(NAME) #NAME,
34 /* Default timeout policy in seconds. */
35 static unsigned int ct_dpif_netdev_tp_def
[] = {
36 [CT_DPIF_TP_ATTR_TCP_SYN_SENT
] = 30,
37 [CT_DPIF_TP_ATTR_TCP_SYN_RECV
] = 30,
38 [CT_DPIF_TP_ATTR_TCP_ESTABLISHED
] = 24 * 60 * 60,
39 [CT_DPIF_TP_ATTR_TCP_FIN_WAIT
] = 15 * 60,
40 [CT_DPIF_TP_ATTR_TCP_TIME_WAIT
] = 45,
41 [CT_DPIF_TP_ATTR_TCP_CLOSE
] = 30,
42 [CT_DPIF_TP_ATTR_UDP_FIRST
] = 60,
43 [CT_DPIF_TP_ATTR_UDP_SINGLE
] = 60,
44 [CT_DPIF_TP_ATTR_UDP_MULTIPLE
] = 30,
45 [CT_DPIF_TP_ATTR_ICMP_FIRST
] = 60,
46 [CT_DPIF_TP_ATTR_ICMP_REPLY
] = 30,
49 static struct timeout_policy
*
50 timeout_policy_lookup(struct conntrack
*ct
, int32_t tp_id
)
51 OVS_REQUIRES(ct
->ct_lock
)
53 struct timeout_policy
*tp
;
56 hash
= hash_int(tp_id
, ct
->hash_basis
);
57 HMAP_FOR_EACH_IN_BUCKET (tp
, node
, hash
, &ct
->timeout_policies
) {
58 if (tp
->policy
.id
== tp_id
) {
65 struct timeout_policy
*
66 timeout_policy_get(struct conntrack
*ct
, int32_t tp_id
)
68 struct timeout_policy
*tp
;
70 ovs_mutex_lock(&ct
->ct_lock
);
71 tp
= timeout_policy_lookup(ct
, tp_id
);
73 ovs_mutex_unlock(&ct
->ct_lock
);
77 ovs_mutex_unlock(&ct
->ct_lock
);
82 update_existing_tp(struct timeout_policy
*tp_dst
,
83 const struct timeout_policy
*tp_src
)
85 struct ct_dpif_timeout_policy
*dst
;
86 const struct ct_dpif_timeout_policy
*src
;
89 dst
= &tp_dst
->policy
;
90 src
= &tp_src
->policy
;
92 /* Set the value and present bit to dst if present
95 for (i
= 0; i
< ARRAY_SIZE(dst
->attrs
); i
++) {
96 if (src
->present
& (1 << i
)) {
97 dst
->attrs
[i
] = src
->attrs
[i
];
98 dst
->present
|= (1 << i
);
104 init_default_tp(struct timeout_policy
*tp
, uint32_t tp_id
)
106 tp
->policy
.id
= tp_id
;
107 /* Initialize the timeout value to default, but not
108 * setting the present bit.
110 tp
->policy
.present
= 0;
111 memcpy(tp
->policy
.attrs
, ct_dpif_netdev_tp_def
,
112 sizeof tp
->policy
.attrs
);
116 timeout_policy_create(struct conntrack
*ct
,
117 struct timeout_policy
*new_tp
)
118 OVS_REQUIRES(ct
->ct_lock
)
120 uint32_t tp_id
= new_tp
->policy
.id
;
121 struct timeout_policy
*tp
;
124 tp
= xzalloc(sizeof *tp
);
125 init_default_tp(tp
, tp_id
);
126 update_existing_tp(tp
, new_tp
);
127 hash
= hash_int(tp_id
, ct
->hash_basis
);
128 hmap_insert(&ct
->timeout_policies
, &tp
->node
, hash
);
132 timeout_policy_clean(struct conntrack
*ct
, struct timeout_policy
*tp
)
133 OVS_REQUIRES(ct
->ct_lock
)
135 hmap_remove(&ct
->timeout_policies
, &tp
->node
);
140 timeout_policy_delete__(struct conntrack
*ct
, uint32_t tp_id
)
141 OVS_REQUIRES(ct
->ct_lock
)
144 struct timeout_policy
*tp
= timeout_policy_lookup(ct
, tp_id
);
147 timeout_policy_clean(ct
, tp
);
149 VLOG_WARN_RL(&rl
, "Failed to delete a non-existent timeout "
150 "policy: id=%d", tp_id
);
157 timeout_policy_delete(struct conntrack
*ct
, uint32_t tp_id
)
161 ovs_mutex_lock(&ct
->ct_lock
);
162 err
= timeout_policy_delete__(ct
, tp_id
);
163 ovs_mutex_unlock(&ct
->ct_lock
);
168 timeout_policy_init(struct conntrack
*ct
)
169 OVS_REQUIRES(ct
->ct_lock
)
171 struct timeout_policy tp
;
173 hmap_init(&ct
->timeout_policies
);
175 /* Create default timeout policy. */
176 memset(&tp
, 0, sizeof tp
);
177 tp
.policy
.id
= DEFAULT_TP_ID
;
178 timeout_policy_create(ct
, &tp
);
182 timeout_policy_update(struct conntrack
*ct
,
183 struct timeout_policy
*new_tp
)
186 uint32_t tp_id
= new_tp
->policy
.id
;
188 ovs_mutex_lock(&ct
->ct_lock
);
189 struct timeout_policy
*tp
= timeout_policy_lookup(ct
, tp_id
);
191 err
= timeout_policy_delete__(ct
, tp_id
);
193 timeout_policy_create(ct
, new_tp
);
194 ovs_mutex_unlock(&ct
->ct_lock
);
198 static enum ct_dpif_tp_attr
199 tm_to_ct_dpif_tp(enum ct_timeout tm
)
202 case CT_TM_TCP_FIRST_PACKET
:
203 return CT_DPIF_TP_ATTR_TCP_SYN_SENT
;
204 case CT_TM_TCP_OPENING
:
205 return CT_DPIF_TP_ATTR_TCP_SYN_RECV
;
206 case CT_TM_TCP_ESTABLISHED
:
207 return CT_DPIF_TP_ATTR_TCP_ESTABLISHED
;
208 case CT_TM_TCP_CLOSING
:
209 return CT_DPIF_TP_ATTR_TCP_FIN_WAIT
;
210 case CT_TM_TCP_FIN_WAIT
:
211 return CT_DPIF_TP_ATTR_TCP_TIME_WAIT
;
212 case CT_TM_TCP_CLOSED
:
213 return CT_DPIF_TP_ATTR_TCP_CLOSE
;
214 case CT_TM_OTHER_FIRST
:
215 return CT_DPIF_TP_ATTR_UDP_FIRST
;
216 case CT_TM_OTHER_BIDIR
:
217 return CT_DPIF_TP_ATTR_UDP_MULTIPLE
;
218 case CT_TM_OTHER_MULTIPLE
:
219 return CT_DPIF_TP_ATTR_UDP_SINGLE
;
220 case CT_TM_ICMP_FIRST
:
221 return CT_DPIF_TP_ATTR_ICMP_FIRST
;
222 case CT_TM_ICMP_REPLY
:
223 return CT_DPIF_TP_ATTR_ICMP_REPLY
;
230 return CT_DPIF_TP_ATTR_MAX
;
234 conn_update_expiration__(struct conntrack
*ct
, struct conn
*conn
,
235 enum ct_timeout tm
, long long now
,
237 OVS_REQUIRES(conn
->lock
)
239 ovs_mutex_unlock(&conn
->lock
);
241 ovs_mutex_lock(&ct
->ct_lock
);
242 ovs_mutex_lock(&conn
->lock
);
243 if (!conn
->cleaned
) {
244 conn
->expiration
= now
+ tp_value
* 1000;
245 ovs_list_remove(&conn
->exp_node
);
246 ovs_list_push_back(&ct
->exp_lists
[tm
], &conn
->exp_node
);
248 ovs_mutex_unlock(&conn
->lock
);
249 ovs_mutex_unlock(&ct
->ct_lock
);
251 ovs_mutex_lock(&conn
->lock
);
254 /* The conn entry lock must be held on entry and exit. */
256 conn_update_expiration(struct conntrack
*ct
, struct conn
*conn
,
257 enum ct_timeout tm
, long long now
)
258 OVS_REQUIRES(conn
->lock
)
260 struct timeout_policy
*tp
;
263 ovs_mutex_unlock(&conn
->lock
);
265 ovs_mutex_lock(&ct
->ct_lock
);
266 ovs_mutex_lock(&conn
->lock
);
267 tp
= timeout_policy_lookup(ct
, conn
->tp_id
);
269 val
= tp
->policy
.attrs
[tm_to_ct_dpif_tp(tm
)];
271 val
= ct_dpif_netdev_tp_def
[tm_to_ct_dpif_tp(tm
)];
273 ovs_mutex_unlock(&conn
->lock
);
274 ovs_mutex_unlock(&ct
->ct_lock
);
276 ovs_mutex_lock(&conn
->lock
);
277 VLOG_DBG_RL(&rl
, "Update timeout %s zone=%u with policy id=%d "
279 ct_timeout_str
[tm
], conn
->key
.zone
, conn
->tp_id
, val
);
281 conn_update_expiration__(ct
, conn
, tm
, now
, val
);
285 conn_init_expiration__(struct conntrack
*ct
, struct conn
*conn
,
286 enum ct_timeout tm
, long long now
,
289 conn
->expiration
= now
+ tp_value
* 1000;
290 ovs_list_push_back(&ct
->exp_lists
[tm
], &conn
->exp_node
);
293 /* ct_lock must be held. */
295 conn_init_expiration(struct conntrack
*ct
, struct conn
*conn
,
296 enum ct_timeout tm
, long long now
)
297 OVS_REQUIRES(ct
->ct_lock
)
299 struct timeout_policy
*tp
;
302 tp
= timeout_policy_lookup(ct
, conn
->tp_id
);
304 val
= tp
->policy
.attrs
[tm_to_ct_dpif_tp(tm
)];
306 val
= ct_dpif_netdev_tp_def
[tm_to_ct_dpif_tp(tm
)];
309 VLOG_DBG_RL(&rl
, "Init timeout %s zone=%u with policy id=%d val=%u sec.",
310 ct_timeout_str
[tm
], conn
->key
.zone
, conn
->tp_id
, val
);
312 conn_init_expiration__(ct
, conn
, tm
, now
, val
);