]> git.proxmox.com Git - mirror_ovs.git/blame - lib/tc.c
compat: Update tc compatibility header
[mirror_ovs.git] / lib / tc.c
CommitLineData
c1c5c723 1/*
ef3767f5 2 * Copyright (c) 2009-2017 Nicira, Inc.
f98e418f 3 * Copyright (c) 2016 Mellanox Technologies, Ltd.
c1c5c723
PB
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include <config.h>
19#include "tc.h"
ef3767f5 20
c1c5c723 21#include <errno.h>
f98e418f
RD
22#include <linux/if_ether.h>
23#include <linux/rtnetlink.h>
24#include <linux/tc_act/tc_gact.h>
25#include <linux/tc_act/tc_mirred.h>
26#include <linux/tc_act/tc_tunnel_key.h>
27#include <linux/tc_act/tc_vlan.h>
28#include <linux/gen_stats.h>
29#include <net/if.h>
8c1e74d1 30#include <unistd.h>
ef3767f5 31
f98e418f 32#include "byte-order.h"
c1c5c723
PB
33#include "netlink-socket.h"
34#include "netlink.h"
35#include "openvswitch/ofpbuf.h"
36#include "openvswitch/vlog.h"
f98e418f
RD
37#include "packets.h"
38#include "timeval.h"
ef3767f5 39#include "unaligned.h"
c1c5c723
PB
40
41VLOG_DEFINE_THIS_MODULE(tc);
42
f98e418f
RD
43static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5);
44
691d20cb
PB
45enum tc_offload_policy {
46 TC_POLICY_NONE,
47 TC_POLICY_SKIP_SW,
48 TC_POLICY_SKIP_HW
49};
50
51static enum tc_offload_policy tc_policy = TC_POLICY_NONE;
52
c1c5c723
PB
53struct tcmsg *
54tc_make_request(int ifindex, int type, unsigned int flags,
55 struct ofpbuf *request)
56{
57 struct tcmsg *tcmsg;
58
59 ofpbuf_init(request, 512);
60 nl_msg_put_nlmsghdr(request, sizeof *tcmsg, type, NLM_F_REQUEST | flags);
61 tcmsg = ofpbuf_put_zeros(request, sizeof *tcmsg);
62 tcmsg->tcm_family = AF_UNSPEC;
63 tcmsg->tcm_ifindex = ifindex;
64 /* Caller should fill in tcmsg->tcm_handle. */
65 /* Caller should fill in tcmsg->tcm_parent. */
66
67 return tcmsg;
68}
69
70int
71tc_transact(struct ofpbuf *request, struct ofpbuf **replyp)
72{
73 int error = nl_transact(NETLINK_ROUTE, request, replyp);
74 ofpbuf_uninit(request);
75 return error;
76}
77
78/* Adds or deletes a root ingress qdisc on device with specified ifindex.
79 *
80 * This function is equivalent to running the following when 'add' is true:
81 * /sbin/tc qdisc add dev <devname> handle ffff: ingress
82 *
83 * This function is equivalent to running the following when 'add' is false:
84 * /sbin/tc qdisc del dev <devname> handle ffff: ingress
85 *
86 * Where dev <devname> is the device with specified ifindex name.
87 *
88 * The configuration and stats may be seen with the following command:
89 * /sbin/tc -s qdisc show dev <devname>
90 *
91 * Returns 0 if successful, otherwise a positive errno value.
92 */
93int
94tc_add_del_ingress_qdisc(int ifindex, bool add)
95{
96 struct ofpbuf request;
97 struct tcmsg *tcmsg;
98 int error;
99 int type = add ? RTM_NEWQDISC : RTM_DELQDISC;
100 int flags = add ? NLM_F_EXCL | NLM_F_CREATE : 0;
101
102 tcmsg = tc_make_request(ifindex, type, flags, &request);
209832d5 103 tcmsg->tcm_handle = TC_H_MAKE(TC_H_INGRESS, 0);
c1c5c723
PB
104 tcmsg->tcm_parent = TC_H_INGRESS;
105 nl_msg_put_string(&request, TCA_KIND, "ingress");
106 nl_msg_put_unspec(&request, TCA_OPTIONS, NULL, 0);
107
108 error = tc_transact(&request, NULL);
109 if (error) {
110 /* If we're deleting the qdisc, don't worry about some of the
111 * error conditions. */
112 if (!add && (error == ENOENT || error == EINVAL)) {
113 return 0;
114 }
115 return error;
116 }
117
118 return 0;
119}
f98e418f
RD
120
121static const struct nl_policy tca_policy[] = {
122 [TCA_KIND] = { .type = NL_A_STRING, .optional = false, },
123 [TCA_OPTIONS] = { .type = NL_A_NESTED, .optional = false, },
124 [TCA_STATS] = { .type = NL_A_UNSPEC,
125 .min_len = sizeof(struct tc_stats), .optional = true, },
126 [TCA_STATS2] = { .type = NL_A_NESTED, .optional = true, },
127};
128
129static const struct nl_policy tca_flower_policy[] = {
130 [TCA_FLOWER_CLASSID] = { .type = NL_A_U32, .optional = true, },
131 [TCA_FLOWER_INDEV] = { .type = NL_A_STRING, .max_len = IFNAMSIZ,
132 .optional = true, },
133 [TCA_FLOWER_KEY_ETH_SRC] = { .type = NL_A_UNSPEC,
134 .min_len = ETH_ALEN, .optional = true, },
135 [TCA_FLOWER_KEY_ETH_DST] = { .type = NL_A_UNSPEC,
136 .min_len = ETH_ALEN, .optional = true, },
137 [TCA_FLOWER_KEY_ETH_SRC_MASK] = { .type = NL_A_UNSPEC,
138 .min_len = ETH_ALEN,
139 .optional = true, },
140 [TCA_FLOWER_KEY_ETH_DST_MASK] = { .type = NL_A_UNSPEC,
141 .min_len = ETH_ALEN,
142 .optional = true, },
143 [TCA_FLOWER_KEY_ETH_TYPE] = { .type = NL_A_U16, .optional = false, },
144 [TCA_FLOWER_FLAGS] = { .type = NL_A_U32, .optional = false, },
145 [TCA_FLOWER_ACT] = { .type = NL_A_NESTED, .optional = false, },
146 [TCA_FLOWER_KEY_IP_PROTO] = { .type = NL_A_U8, .optional = true, },
147 [TCA_FLOWER_KEY_IPV4_SRC] = { .type = NL_A_U32, .optional = true, },
148 [TCA_FLOWER_KEY_IPV4_DST] = {.type = NL_A_U32, .optional = true, },
149 [TCA_FLOWER_KEY_IPV4_SRC_MASK] = { .type = NL_A_U32, .optional = true, },
150 [TCA_FLOWER_KEY_IPV4_DST_MASK] = { .type = NL_A_U32, .optional = true, },
151 [TCA_FLOWER_KEY_IPV6_SRC] = { .type = NL_A_UNSPEC,
152 .min_len = sizeof(struct in6_addr),
153 .optional = true, },
154 [TCA_FLOWER_KEY_IPV6_DST] = { .type = NL_A_UNSPEC,
155 .min_len = sizeof(struct in6_addr),
156 .optional = true, },
157 [TCA_FLOWER_KEY_IPV6_SRC_MASK] = { .type = NL_A_UNSPEC,
158 .min_len = sizeof(struct in6_addr),
159 .optional = true, },
160 [TCA_FLOWER_KEY_IPV6_DST_MASK] = { .type = NL_A_UNSPEC,
161 .min_len = sizeof(struct in6_addr),
162 .optional = true, },
163 [TCA_FLOWER_KEY_TCP_SRC] = { .type = NL_A_U16, .optional = true, },
164 [TCA_FLOWER_KEY_TCP_DST] = { .type = NL_A_U16, .optional = true, },
165 [TCA_FLOWER_KEY_TCP_SRC_MASK] = { .type = NL_A_U16, .optional = true, },
166 [TCA_FLOWER_KEY_TCP_DST_MASK] = { .type = NL_A_U16, .optional = true, },
167 [TCA_FLOWER_KEY_UDP_SRC] = { .type = NL_A_U16, .optional = true, },
168 [TCA_FLOWER_KEY_UDP_DST] = { .type = NL_A_U16, .optional = true, },
169 [TCA_FLOWER_KEY_UDP_SRC_MASK] = { .type = NL_A_U16, .optional = true, },
170 [TCA_FLOWER_KEY_UDP_DST_MASK] = { .type = NL_A_U16, .optional = true, },
4862b4e5
VB
171 [TCA_FLOWER_KEY_SCTP_SRC] = { .type = NL_A_U16, .optional = true, },
172 [TCA_FLOWER_KEY_SCTP_DST] = { .type = NL_A_U16, .optional = true, },
173 [TCA_FLOWER_KEY_SCTP_SRC_MASK] = { .type = NL_A_U16, .optional = true, },
174 [TCA_FLOWER_KEY_SCTP_DST_MASK] = { .type = NL_A_U16, .optional = true, },
f98e418f
RD
175 [TCA_FLOWER_KEY_VLAN_ID] = { .type = NL_A_U16, .optional = true, },
176 [TCA_FLOWER_KEY_VLAN_PRIO] = { .type = NL_A_U8, .optional = true, },
177 [TCA_FLOWER_KEY_VLAN_ETH_TYPE] = { .type = NL_A_U16, .optional = true, },
178 [TCA_FLOWER_KEY_ENC_KEY_ID] = { .type = NL_A_U32, .optional = true, },
179 [TCA_FLOWER_KEY_ENC_IPV4_SRC] = { .type = NL_A_U32, .optional = true, },
180 [TCA_FLOWER_KEY_ENC_IPV4_DST] = { .type = NL_A_U32, .optional = true, },
181 [TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NL_A_U32,
182 .optional = true, },
183 [TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NL_A_U32,
184 .optional = true, },
185 [TCA_FLOWER_KEY_ENC_IPV6_SRC] = { .type = NL_A_UNSPEC,
186 .min_len = sizeof(struct in6_addr),
187 .optional = true, },
188 [TCA_FLOWER_KEY_ENC_IPV6_DST] = { .type = NL_A_UNSPEC,
189 .min_len = sizeof(struct in6_addr),
190 .optional = true, },
191 [TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .type = NL_A_UNSPEC,
192 .min_len = sizeof(struct in6_addr),
193 .optional = true, },
194 [TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .type = NL_A_UNSPEC,
195 .min_len = sizeof(struct in6_addr),
196 .optional = true, },
197 [TCA_FLOWER_KEY_ENC_UDP_DST_PORT] = { .type = NL_A_U16,
198 .optional = true, },
199};
200
201static void
202nl_parse_flower_eth(struct nlattr **attrs, struct tc_flower *flower)
203{
204 const struct eth_addr *eth;
205
206 if (attrs[TCA_FLOWER_KEY_ETH_SRC_MASK]) {
207 eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ETH_SRC], ETH_ALEN);
208 memcpy(&flower->key.src_mac, eth, sizeof flower->key.src_mac);
209
210 eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ETH_SRC_MASK], ETH_ALEN);
211 memcpy(&flower->mask.src_mac, eth, sizeof flower->mask.src_mac);
212 }
213 if (attrs[TCA_FLOWER_KEY_ETH_DST_MASK]) {
214 eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ETH_DST], ETH_ALEN);
215 memcpy(&flower->key.dst_mac, eth, sizeof flower->key.dst_mac);
216
217 eth = nl_attr_get_unspec(attrs[TCA_FLOWER_KEY_ETH_DST_MASK], ETH_ALEN);
218 memcpy(&flower->mask.dst_mac, eth, sizeof flower->mask.dst_mac);
219 }
220}
221
222static void
223nl_parse_flower_vlan(struct nlattr **attrs, struct tc_flower *flower)
224{
225 if (flower->key.eth_type != htons(ETH_TYPE_VLAN)) {
226 return;
227 }
228
229 flower->key.encap_eth_type =
230 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_ETH_TYPE]);
231
232 if (attrs[TCA_FLOWER_KEY_VLAN_ID]) {
233 flower->key.vlan_id =
234 nl_attr_get_u16(attrs[TCA_FLOWER_KEY_VLAN_ID]);
235 }
236 if (attrs[TCA_FLOWER_KEY_VLAN_PRIO]) {
237 flower->key.vlan_prio =
238 nl_attr_get_u8(attrs[TCA_FLOWER_KEY_VLAN_PRIO]);
239 }
240}
241
242static void
243nl_parse_flower_tunnel(struct nlattr **attrs, struct tc_flower *flower)
244{
245 if (attrs[TCA_FLOWER_KEY_ENC_KEY_ID]) {
246 ovs_be32 id = nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_KEY_ID]);
247
248 flower->tunnel.id = be32_to_be64(id);
249 }
250 if (attrs[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK]) {
251 flower->tunnel.ipv4.ipv4_src =
252 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_IPV4_SRC]);
253 }
254 if (attrs[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK]) {
255 flower->tunnel.ipv4.ipv4_dst =
256 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_IPV4_DST]);
257 }
258 if (attrs[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK]) {
259 flower->tunnel.ipv6.ipv6_src =
260 nl_attr_get_in6_addr(attrs[TCA_FLOWER_KEY_ENC_IPV6_SRC]);
261 }
262 if (attrs[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK]) {
263 flower->tunnel.ipv6.ipv6_dst =
264 nl_attr_get_in6_addr(attrs[TCA_FLOWER_KEY_ENC_IPV6_DST]);
265 }
266 if (attrs[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]) {
267 flower->tunnel.tp_dst =
268 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]);
269 }
270}
271
272static void
273nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) {
274 uint8_t ip_proto = 0;
275 struct tc_flower_key *key = &flower->key;
276 struct tc_flower_key *mask = &flower->mask;
277
278 if (attrs[TCA_FLOWER_KEY_IP_PROTO]) {
279 ip_proto = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_IP_PROTO]);
280 key->ip_proto = ip_proto;
281 mask->ip_proto = UINT8_MAX;
282 }
283
284 if (attrs[TCA_FLOWER_KEY_IPV4_SRC_MASK]) {
285 key->ipv4.ipv4_src =
286 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_IPV4_SRC]);
287 mask->ipv4.ipv4_src =
288 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_IPV4_SRC_MASK]);
289 }
290 if (attrs[TCA_FLOWER_KEY_IPV4_DST_MASK]) {
291 key->ipv4.ipv4_dst =
292 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_IPV4_DST]);
293 mask->ipv4.ipv4_dst =
294 nl_attr_get_be32(attrs[TCA_FLOWER_KEY_IPV4_DST_MASK]);
295 }
296 if (attrs[TCA_FLOWER_KEY_IPV6_SRC_MASK]) {
297 struct nlattr *attr = attrs[TCA_FLOWER_KEY_IPV6_SRC];
298 struct nlattr *attr_mask = attrs[TCA_FLOWER_KEY_IPV6_SRC_MASK];
299
300 key->ipv6.ipv6_src = nl_attr_get_in6_addr(attr);
301 mask->ipv6.ipv6_src = nl_attr_get_in6_addr(attr_mask);
302 }
303 if (attrs[TCA_FLOWER_KEY_IPV6_DST_MASK]) {
304 struct nlattr *attr = attrs[TCA_FLOWER_KEY_IPV6_DST];
305 struct nlattr *attr_mask = attrs[TCA_FLOWER_KEY_IPV6_DST_MASK];
306
307 key->ipv6.ipv6_dst = nl_attr_get_in6_addr(attr);
308 mask->ipv6.ipv6_dst = nl_attr_get_in6_addr(attr_mask);
309 }
310
311 if (ip_proto == IPPROTO_TCP) {
312 if (attrs[TCA_FLOWER_KEY_TCP_SRC_MASK]) {
2b1d9fa9 313 key->tcp_src =
f98e418f 314 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_TCP_SRC]);
2b1d9fa9 315 mask->tcp_src =
f98e418f
RD
316 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_TCP_SRC_MASK]);
317 }
318 if (attrs[TCA_FLOWER_KEY_TCP_DST_MASK]) {
2b1d9fa9 319 key->tcp_dst =
f98e418f 320 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_TCP_DST]);
2b1d9fa9 321 mask->tcp_dst =
f98e418f
RD
322 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_TCP_DST_MASK]);
323 }
324 } else if (ip_proto == IPPROTO_UDP) {
325 if (attrs[TCA_FLOWER_KEY_UDP_SRC_MASK]) {
2b1d9fa9
PB
326 key->udp_src = nl_attr_get_be16(attrs[TCA_FLOWER_KEY_UDP_SRC]);
327 mask->udp_src =
f98e418f
RD
328 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_UDP_SRC_MASK]);
329 }
330 if (attrs[TCA_FLOWER_KEY_UDP_DST_MASK]) {
2b1d9fa9
PB
331 key->udp_dst = nl_attr_get_be16(attrs[TCA_FLOWER_KEY_UDP_DST]);
332 mask->udp_dst =
f98e418f
RD
333 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_UDP_DST_MASK]);
334 }
4862b4e5
VB
335 } else if (ip_proto == IPPROTO_SCTP) {
336 if (attrs[TCA_FLOWER_KEY_SCTP_SRC_MASK]) {
2b1d9fa9
PB
337 key->sctp_src = nl_attr_get_be16(attrs[TCA_FLOWER_KEY_SCTP_SRC]);
338 mask->sctp_src =
4862b4e5
VB
339 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_SCTP_SRC_MASK]);
340 }
341 if (attrs[TCA_FLOWER_KEY_SCTP_DST_MASK]) {
2b1d9fa9
PB
342 key->sctp_dst = nl_attr_get_be16(attrs[TCA_FLOWER_KEY_SCTP_DST]);
343 mask->sctp_dst =
4862b4e5
VB
344 nl_attr_get_be16(attrs[TCA_FLOWER_KEY_SCTP_DST_MASK]);
345 }
f98e418f
RD
346 }
347}
348
349static const struct nl_policy tunnel_key_policy[] = {
350 [TCA_TUNNEL_KEY_PARMS] = { .type = NL_A_UNSPEC,
351 .min_len = sizeof(struct tc_tunnel_key),
352 .optional = false, },
353 [TCA_TUNNEL_KEY_ENC_IPV4_SRC] = { .type = NL_A_U32, .optional = true, },
354 [TCA_TUNNEL_KEY_ENC_IPV4_DST] = { .type = NL_A_U32, .optional = true, },
355 [TCA_TUNNEL_KEY_ENC_IPV6_SRC] = { .type = NL_A_UNSPEC,
356 .min_len = sizeof(struct in6_addr),
357 .optional = true, },
358 [TCA_TUNNEL_KEY_ENC_IPV6_DST] = { .type = NL_A_UNSPEC,
359 .min_len = sizeof(struct in6_addr),
360 .optional = true, },
361 [TCA_TUNNEL_KEY_ENC_KEY_ID] = { .type = NL_A_U32, .optional = true, },
362 [TCA_TUNNEL_KEY_ENC_DST_PORT] = { .type = NL_A_U16, .optional = true, },
363};
364
365static int
366nl_parse_act_tunnel_key(struct nlattr *options, struct tc_flower *flower)
367{
368 struct nlattr *tun_attrs[ARRAY_SIZE(tunnel_key_policy)];
369 const struct nlattr *tun_parms;
370 const struct tc_tunnel_key *tun;
371
372 if (!nl_parse_nested(options, tunnel_key_policy, tun_attrs,
373 ARRAY_SIZE(tunnel_key_policy))) {
374 VLOG_ERR_RL(&error_rl, "failed to parse tunnel_key action options");
375 return EPROTO;
376 }
377
378 tun_parms = tun_attrs[TCA_TUNNEL_KEY_PARMS];
379 tun = nl_attr_get_unspec(tun_parms, sizeof *tun);
380 if (tun->t_action == TCA_TUNNEL_KEY_ACT_SET) {
381 struct nlattr *id = tun_attrs[TCA_TUNNEL_KEY_ENC_KEY_ID];
382 struct nlattr *dst_port = tun_attrs[TCA_TUNNEL_KEY_ENC_DST_PORT];
383 struct nlattr *ipv4_src = tun_attrs[TCA_TUNNEL_KEY_ENC_IPV4_SRC];
384 struct nlattr *ipv4_dst = tun_attrs[TCA_TUNNEL_KEY_ENC_IPV4_DST];
385 struct nlattr *ipv6_src = tun_attrs[TCA_TUNNEL_KEY_ENC_IPV6_SRC];
386 struct nlattr *ipv6_dst = tun_attrs[TCA_TUNNEL_KEY_ENC_IPV6_DST];
387
388 flower->set.set = true;
389 flower->set.ipv4.ipv4_src = ipv4_src ? nl_attr_get_be32(ipv4_src) : 0;
390 flower->set.ipv4.ipv4_dst = ipv4_dst ? nl_attr_get_be32(ipv4_dst) : 0;
391 if (ipv6_src) {
392 flower->set.ipv6.ipv6_src = nl_attr_get_in6_addr(ipv6_src);
393 }
394 if (ipv6_dst) {
395 flower->set.ipv6.ipv6_dst = nl_attr_get_in6_addr(ipv6_dst);
396 }
397 flower->set.id = id ? be32_to_be64(nl_attr_get_be32(id)) : 0;
398 flower->set.tp_dst = dst_port ? nl_attr_get_be16(dst_port) : 0;
399 } else if (tun->t_action == TCA_TUNNEL_KEY_ACT_RELEASE) {
400 flower->tunnel.tunnel = true;
401 } else {
402 VLOG_ERR_RL(&error_rl, "unknown tunnel actions: %d, %d",
403 tun->action, tun->t_action);
404 return EINVAL;
405 }
406 return 0;
407}
408
409static const struct nl_policy gact_policy[] = {
410 [TCA_GACT_PARMS] = { .type = NL_A_UNSPEC,
411 .min_len = sizeof(struct tc_gact),
412 .optional = false, },
413 [TCA_GACT_TM] = { .type = NL_A_UNSPEC,
414 .min_len = sizeof(struct tcf_t),
415 .optional = false, },
416};
417
8c1e74d1
PB
418static int
419get_user_hz(void)
420{
421 static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
422 static int user_hz = 100;
423
424 if (ovsthread_once_start(&once)) {
425 user_hz = sysconf(_SC_CLK_TCK);
426 ovsthread_once_done(&once);
427 }
428
429 return user_hz;
430}
f98e418f
RD
431
432static void
433nl_parse_tcf(const struct tcf_t *tm, struct tc_flower *flower)
434{
8c1e74d1 435 flower->lastused = time_msec() - (tm->lastuse * 1000 / get_user_hz());
f98e418f
RD
436}
437
438static int
439nl_parse_act_drop(struct nlattr *options, struct tc_flower *flower)
440{
441 struct nlattr *gact_attrs[ARRAY_SIZE(gact_policy)];
442 const struct tc_gact *p;
443 struct nlattr *gact_parms;
444 const struct tcf_t *tm;
445
446 if (!nl_parse_nested(options, gact_policy, gact_attrs,
447 ARRAY_SIZE(gact_policy))) {
448 VLOG_ERR_RL(&error_rl, "failed to parse gact action options");
449 return EPROTO;
450 }
451
452 gact_parms = gact_attrs[TCA_GACT_PARMS];
453 p = nl_attr_get_unspec(gact_parms, sizeof *p);
454
455 if (p->action != TC_ACT_SHOT) {
456 VLOG_ERR_RL(&error_rl, "unknown gact action: %d", p->action);
457 return EINVAL;
458 }
459
460 tm = nl_attr_get_unspec(gact_attrs[TCA_GACT_TM], sizeof *tm);
461 nl_parse_tcf(tm, flower);
462
463 return 0;
464}
465
466static const struct nl_policy mirred_policy[] = {
467 [TCA_MIRRED_PARMS] = { .type = NL_A_UNSPEC,
468 .min_len = sizeof(struct tc_mirred),
469 .optional = false, },
470 [TCA_MIRRED_TM] = { .type = NL_A_UNSPEC,
471 .min_len = sizeof(struct tcf_t),
472 .optional = false, },
473};
474
475static int
476nl_parse_act_mirred(struct nlattr *options, struct tc_flower *flower)
477{
478
479 struct nlattr *mirred_attrs[ARRAY_SIZE(mirred_policy)];
480 const struct tc_mirred *m;
481 const struct nlattr *mirred_parms;
482 const struct tcf_t *tm;
483 struct nlattr *mirred_tm;
484
485 if (!nl_parse_nested(options, mirred_policy, mirred_attrs,
486 ARRAY_SIZE(mirred_policy))) {
487 VLOG_ERR_RL(&error_rl, "failed to parse mirred action options");
488 return EPROTO;
489 }
490
491 mirred_parms = mirred_attrs[TCA_MIRRED_PARMS];
492 m = nl_attr_get_unspec(mirred_parms, sizeof *m);
493
494 if (m->action != TC_ACT_STOLEN || m->eaction != TCA_EGRESS_REDIR) {
495 VLOG_ERR_RL(&error_rl, "unknown mirred action: %d, %d, %d",
496 m->action, m->eaction, m->ifindex);
497 return EINVAL;
498 }
499
500 flower->ifindex_out = m->ifindex;
501
502 mirred_tm = mirred_attrs[TCA_MIRRED_TM];
503 tm = nl_attr_get_unspec(mirred_tm, sizeof *tm);
504 nl_parse_tcf(tm, flower);
505
506 return 0;
507}
508
509static const struct nl_policy vlan_policy[] = {
510 [TCA_VLAN_PARMS] = { .type = NL_A_UNSPEC,
511 .min_len = sizeof(struct tc_vlan),
512 .optional = false, },
513 [TCA_VLAN_PUSH_VLAN_ID] = { .type = NL_A_U16, .optional = true, },
514 [TCA_VLAN_PUSH_VLAN_PROTOCOL] = { .type = NL_A_U16, .optional = true, },
515 [TCA_VLAN_PUSH_VLAN_PRIORITY] = { .type = NL_A_U8, .optional = true, },
516};
517
518static int
519nl_parse_act_vlan(struct nlattr *options, struct tc_flower *flower)
520{
521 struct nlattr *vlan_attrs[ARRAY_SIZE(vlan_policy)];
522 const struct tc_vlan *v;
523 const struct nlattr *vlan_parms;
524
525 if (!nl_parse_nested(options, vlan_policy, vlan_attrs,
526 ARRAY_SIZE(vlan_policy))) {
527 VLOG_ERR_RL(&error_rl, "failed to parse vlan action options");
528 return EPROTO;
529 }
530
531 vlan_parms = vlan_attrs[TCA_VLAN_PARMS];
532 v = nl_attr_get_unspec(vlan_parms, sizeof *v);
533 if (v->v_action == TCA_VLAN_ACT_PUSH) {
534 struct nlattr *vlan_id = vlan_attrs[TCA_VLAN_PUSH_VLAN_ID];
535 struct nlattr *vlan_prio = vlan_attrs[TCA_VLAN_PUSH_VLAN_PRIORITY];
536
537 flower->vlan_push_id = nl_attr_get_u16(vlan_id);
538 flower->vlan_push_prio = vlan_prio ? nl_attr_get_u8(vlan_prio) : 0;
539 } else if (v->v_action == TCA_VLAN_ACT_POP) {
540 flower->vlan_pop = 1;
541 } else {
542 VLOG_ERR_RL(&error_rl, "unknown vlan action: %d, %d",
543 v->action, v->v_action);
544 return EINVAL;
545 }
546 return 0;
547}
548
549static const struct nl_policy act_policy[] = {
550 [TCA_ACT_KIND] = { .type = NL_A_STRING, .optional = false, },
551 [TCA_ACT_COOKIE] = { .type = NL_A_UNSPEC, .optional = true, },
552 [TCA_ACT_OPTIONS] = { .type = NL_A_NESTED, .optional = false, },
553 [TCA_ACT_STATS] = { .type = NL_A_NESTED, .optional = false, },
554};
555
556static const struct nl_policy stats_policy[] = {
557 [TCA_STATS_BASIC] = { .type = NL_A_UNSPEC,
558 .min_len = sizeof(struct gnet_stats_basic),
559 .optional = false, },
560};
561
562static int
563nl_parse_single_action(struct nlattr *action, struct tc_flower *flower)
564{
565 struct nlattr *act_options;
566 struct nlattr *act_stats;
567 struct nlattr *act_cookie;
568 const char *act_kind;
569 struct nlattr *action_attrs[ARRAY_SIZE(act_policy)];
570 struct nlattr *stats_attrs[ARRAY_SIZE(stats_policy)];
571 struct ovs_flow_stats *stats = &flower->stats;
572 const struct gnet_stats_basic *bs;
573
574 if (!nl_parse_nested(action, act_policy, action_attrs,
575 ARRAY_SIZE(act_policy))) {
576 VLOG_ERR_RL(&error_rl, "failed to parse single action options");
577 return EPROTO;
578 }
579
580 act_kind = nl_attr_get_string(action_attrs[TCA_ACT_KIND]);
581 act_options = action_attrs[TCA_ACT_OPTIONS];
582 act_cookie = action_attrs[TCA_ACT_COOKIE];
583
584 if (!strcmp(act_kind, "gact")) {
585 nl_parse_act_drop(act_options, flower);
586 } else if (!strcmp(act_kind, "mirred")) {
587 nl_parse_act_mirred(act_options, flower);
588 } else if (!strcmp(act_kind, "vlan")) {
589 nl_parse_act_vlan(act_options, flower);
590 } else if (!strcmp(act_kind, "tunnel_key")) {
591 nl_parse_act_tunnel_key(act_options, flower);
592 } else {
593 VLOG_ERR_RL(&error_rl, "unknown tc action kind: %s", act_kind);
594 return EINVAL;
595 }
596
597 if (act_cookie) {
598 flower->act_cookie.data = nl_attr_get(act_cookie);
599 flower->act_cookie.len = nl_attr_get_size(act_cookie);
600 }
601
602 act_stats = action_attrs[TCA_ACT_STATS];
603
604 if (!nl_parse_nested(act_stats, stats_policy, stats_attrs,
605 ARRAY_SIZE(stats_policy))) {
606 VLOG_ERR_RL(&error_rl, "failed to parse action stats policy");
607 return EPROTO;
608 }
609
610 bs = nl_attr_get_unspec(stats_attrs[TCA_STATS_BASIC], sizeof *bs);
611 put_32aligned_u64(&stats->n_packets, bs->packets);
612 put_32aligned_u64(&stats->n_bytes, bs->bytes);
613
614 return 0;
615}
616
617#define TCA_ACT_MIN_PRIO 1
618
619static int
620nl_parse_flower_actions(struct nlattr **attrs, struct tc_flower *flower)
621{
622 const struct nlattr *actions = attrs[TCA_FLOWER_ACT];
623 static struct nl_policy actions_orders_policy[TCA_ACT_MAX_PRIO + 1] = {};
624 struct nlattr *actions_orders[ARRAY_SIZE(actions_orders_policy)];
625 const int max_size = ARRAY_SIZE(actions_orders_policy);
626
627 for (int i = TCA_ACT_MIN_PRIO; i < max_size; i++) {
628 actions_orders_policy[i].type = NL_A_NESTED;
629 actions_orders_policy[i].optional = true;
630 }
631
632 if (!nl_parse_nested(actions, actions_orders_policy, actions_orders,
633 ARRAY_SIZE(actions_orders_policy))) {
634 VLOG_ERR_RL(&error_rl, "failed to parse flower order of actions");
635 return EPROTO;
636 }
637
638 for (int i = TCA_ACT_MIN_PRIO; i < max_size; i++) {
639 if (actions_orders[i]) {
640 int err = nl_parse_single_action(actions_orders[i], flower);
641
642 if (err) {
643 return err;
644 }
645 }
646 }
647
648 return 0;
649}
650
651static int
652nl_parse_flower_options(struct nlattr *nl_options, struct tc_flower *flower)
653{
654 struct nlattr *attrs[ARRAY_SIZE(tca_flower_policy)];
655
656 if (!nl_parse_nested(nl_options, tca_flower_policy,
657 attrs, ARRAY_SIZE(tca_flower_policy))) {
658 VLOG_ERR_RL(&error_rl, "failed to parse flower classifier options");
659 return EPROTO;
660 }
661
662 nl_parse_flower_eth(attrs, flower);
663 nl_parse_flower_vlan(attrs, flower);
664 nl_parse_flower_ip(attrs, flower);
665 nl_parse_flower_tunnel(attrs, flower);
666 return nl_parse_flower_actions(attrs, flower);
667}
668
669int
670parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tc_flower *flower)
671{
672 struct tcmsg *tc;
673 struct nlattr *ta[ARRAY_SIZE(tca_policy)];
674 const char *kind;
675
676 if (NLMSG_HDRLEN + sizeof *tc > reply->size) {
677 return EPROTO;
678 }
679
680 memset(flower, 0, sizeof *flower);
681
682 tc = ofpbuf_at_assert(reply, NLMSG_HDRLEN, sizeof *tc);
683 flower->handle = tc->tcm_handle;
684 flower->key.eth_type = (OVS_FORCE ovs_be16) tc_get_minor(tc->tcm_info);
685 flower->mask.eth_type = OVS_BE16_MAX;
686 flower->prio = tc_get_major(tc->tcm_info);
687
688 if (!flower->handle) {
689 return EAGAIN;
690 }
691
692 if (!nl_policy_parse(reply, NLMSG_HDRLEN + sizeof *tc,
693 tca_policy, ta, ARRAY_SIZE(ta))) {
694 VLOG_ERR_RL(&error_rl, "failed to parse tca policy");
695 return EPROTO;
696 }
697
698 kind = nl_attr_get_string(ta[TCA_KIND]);
699 if (strcmp(kind, "flower")) {
700 VLOG_ERR_RL(&error_rl, "failed to parse filter: %s", kind);
701 return EPROTO;
702 }
703
704 return nl_parse_flower_options(ta[TCA_OPTIONS], flower);
705}
706
707int
708tc_dump_flower_start(int ifindex, struct nl_dump *dump)
709{
710 struct ofpbuf request;
711 struct tcmsg *tcmsg;
712
713 tcmsg = tc_make_request(ifindex, RTM_GETTFILTER, NLM_F_DUMP, &request);
714 tcmsg->tcm_parent = TC_INGRESS_PARENT;
715 tcmsg->tcm_info = TC_H_UNSPEC;
716 tcmsg->tcm_handle = 0;
717
718 nl_dump_start(dump, NETLINK_ROUTE, &request);
719 ofpbuf_uninit(&request);
720
721 return 0;
722}
723
724int
725tc_flush(int ifindex)
726{
727 struct ofpbuf request;
728 struct tcmsg *tcmsg;
729
730 tcmsg = tc_make_request(ifindex, RTM_DELTFILTER, NLM_F_ACK, &request);
731 tcmsg->tcm_parent = TC_INGRESS_PARENT;
732 tcmsg->tcm_info = TC_H_UNSPEC;
733
734 return tc_transact(&request, NULL);
735}
736
737int
738tc_del_filter(int ifindex, int prio, int handle)
739{
740 struct ofpbuf request;
741 struct tcmsg *tcmsg;
742 struct ofpbuf *reply;
743 int error;
744
745 tcmsg = tc_make_request(ifindex, RTM_DELTFILTER, NLM_F_ECHO, &request);
746 tcmsg->tcm_parent = TC_INGRESS_PARENT;
747 tcmsg->tcm_info = tc_make_handle(prio, 0);
748 tcmsg->tcm_handle = handle;
749
750 error = tc_transact(&request, &reply);
751 if (!error) {
752 ofpbuf_delete(reply);
753 }
754 return error;
755}
756
757int
758tc_get_flower(int ifindex, int prio, int handle, struct tc_flower *flower)
759{
760 struct ofpbuf request;
761 struct tcmsg *tcmsg;
762 struct ofpbuf *reply;
763 int error;
764
765 tcmsg = tc_make_request(ifindex, RTM_GETTFILTER, NLM_F_ECHO, &request);
766 tcmsg->tcm_parent = TC_INGRESS_PARENT;
767 tcmsg->tcm_info = tc_make_handle(prio, 0);
768 tcmsg->tcm_handle = handle;
769
770 error = tc_transact(&request, &reply);
771 if (error) {
772 return error;
773 }
774
775 error = parse_netlink_to_tc_flower(reply, flower);
776 ofpbuf_delete(reply);
777 return error;
778}
779
691d20cb
PB
780static int
781tc_get_tc_cls_policy(enum tc_offload_policy policy)
782{
783 if (policy == TC_POLICY_SKIP_HW) {
784 return TCA_CLS_FLAGS_SKIP_HW;
785 } else if (policy == TC_POLICY_SKIP_SW) {
786 return TCA_CLS_FLAGS_SKIP_SW;
787 }
788
789 return 0;
790}
791
f98e418f
RD
792static void
793nl_msg_put_act_push_vlan(struct ofpbuf *request, uint16_t vid, uint8_t prio)
794{
795 size_t offset;
796
797 nl_msg_put_string(request, TCA_ACT_KIND, "vlan");
798 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
799 {
800 struct tc_vlan parm = { .action = TC_ACT_PIPE,
801 .v_action = TCA_VLAN_ACT_PUSH };
802
803 nl_msg_put_unspec(request, TCA_VLAN_PARMS, &parm, sizeof parm);
804 nl_msg_put_u16(request, TCA_VLAN_PUSH_VLAN_ID, vid);
805 nl_msg_put_u8(request, TCA_VLAN_PUSH_VLAN_PRIORITY, prio);
806 }
807 nl_msg_end_nested(request, offset);
808}
809
810static void
811nl_msg_put_act_pop_vlan(struct ofpbuf *request)
812{
813 size_t offset;
814
815 nl_msg_put_string(request, TCA_ACT_KIND, "vlan");
816 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
817 {
818 struct tc_vlan parm = { .action = TC_ACT_PIPE,
819 .v_action = TCA_VLAN_ACT_POP };
820
821 nl_msg_put_unspec(request, TCA_VLAN_PARMS, &parm, sizeof parm);
822 }
823 nl_msg_end_nested(request, offset);
824}
825
826static void
827nl_msg_put_act_tunnel_key_release(struct ofpbuf *request)
828{
829 size_t offset;
830
831 nl_msg_put_string(request, TCA_ACT_KIND, "tunnel_key");
832 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
833 {
834 struct tc_tunnel_key tun = { .action = TC_ACT_PIPE,
835 .t_action = TCA_TUNNEL_KEY_ACT_RELEASE };
836
837 nl_msg_put_unspec(request, TCA_TUNNEL_KEY_PARMS, &tun, sizeof tun);
838 }
839 nl_msg_end_nested(request, offset);
840}
841
842static void
843nl_msg_put_act_tunnel_key_set(struct ofpbuf *request, ovs_be64 id,
844 ovs_be32 ipv4_src, ovs_be32 ipv4_dst,
845 struct in6_addr *ipv6_src,
846 struct in6_addr *ipv6_dst,
847 ovs_be16 tp_dst)
848{
849 size_t offset;
850
851 nl_msg_put_string(request, TCA_ACT_KIND, "tunnel_key");
852 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
853 {
854 struct tc_tunnel_key tun = { .action = TC_ACT_PIPE,
855 .t_action = TCA_TUNNEL_KEY_ACT_SET };
856
857 nl_msg_put_unspec(request, TCA_TUNNEL_KEY_PARMS, &tun, sizeof tun);
858
859 ovs_be32 id32 = be64_to_be32(id);
860 nl_msg_put_be32(request, TCA_TUNNEL_KEY_ENC_KEY_ID, id32);
861 if (ipv4_dst) {
862 nl_msg_put_be32(request, TCA_TUNNEL_KEY_ENC_IPV4_SRC, ipv4_src);
863 nl_msg_put_be32(request, TCA_TUNNEL_KEY_ENC_IPV4_DST, ipv4_dst);
864 } else if (!is_all_zeros(ipv6_dst, sizeof *ipv6_dst)) {
865 nl_msg_put_in6_addr(request, TCA_TUNNEL_KEY_ENC_IPV6_DST,
866 ipv6_dst);
867 nl_msg_put_in6_addr(request, TCA_TUNNEL_KEY_ENC_IPV6_SRC,
868 ipv6_src);
869 }
870 nl_msg_put_be16(request, TCA_TUNNEL_KEY_ENC_DST_PORT, tp_dst);
871 }
872 nl_msg_end_nested(request, offset);
873}
874
875static void
876nl_msg_put_act_drop(struct ofpbuf *request)
877{
878 size_t offset;
879
880 nl_msg_put_string(request, TCA_ACT_KIND, "gact");
881 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
882 {
883 struct tc_gact p = { .action = TC_ACT_SHOT };
884
885 nl_msg_put_unspec(request, TCA_GACT_PARMS, &p, sizeof p);
886 }
887 nl_msg_end_nested(request, offset);
888}
889
890static void
891nl_msg_put_act_redirect(struct ofpbuf *request, int ifindex)
892{
893 size_t offset;
894
895 nl_msg_put_string(request, TCA_ACT_KIND, "mirred");
896 offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);
897 {
898 struct tc_mirred m = { .action = TC_ACT_STOLEN,
899 .eaction = TCA_EGRESS_REDIR,
900 .ifindex = ifindex };
901
902 nl_msg_put_unspec(request, TCA_MIRRED_PARMS, &m, sizeof m);
903 }
904 nl_msg_end_nested(request, offset);
905}
906
907static inline void
908nl_msg_put_act_cookie(struct ofpbuf *request, struct tc_cookie *ck) {
909 if (ck->len) {
910 nl_msg_put_unspec(request, TCA_ACT_COOKIE, ck->data, ck->len);
911 }
912}
913
914static void
915nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)
916{
917 size_t offset;
918 size_t act_offset;
919
920 offset = nl_msg_start_nested(request, TCA_FLOWER_ACT);
921 {
922 uint16_t act_index = 1;
923
924 if (flower->set.set) {
925 act_offset = nl_msg_start_nested(request, act_index++);
926 nl_msg_put_act_tunnel_key_set(request, flower->set.id,
927 flower->set.ipv4.ipv4_src,
928 flower->set.ipv4.ipv4_dst,
929 &flower->set.ipv6.ipv6_src,
930 &flower->set.ipv6.ipv6_dst,
931 flower->set.tp_dst);
932 nl_msg_end_nested(request, act_offset);
933 }
934 if (flower->tunnel.tunnel) {
935 act_offset = nl_msg_start_nested(request, act_index++);
936 nl_msg_put_act_tunnel_key_release(request);
937 nl_msg_end_nested(request, act_offset);
938 }
939 if (flower->vlan_pop) {
940 act_offset = nl_msg_start_nested(request, act_index++);
941 nl_msg_put_act_pop_vlan(request);
942 nl_msg_end_nested(request, act_offset);
943 }
944 if (flower->vlan_push_id) {
945 act_offset = nl_msg_start_nested(request, act_index++);
946 nl_msg_put_act_push_vlan(request,
947 flower->vlan_push_id,
948 flower->vlan_push_prio);
949 nl_msg_end_nested(request, act_offset);
950 }
951 if (flower->ifindex_out) {
952 act_offset = nl_msg_start_nested(request, act_index++);
953 nl_msg_put_act_redirect(request, flower->ifindex_out);
954 nl_msg_put_act_cookie(request, &flower->act_cookie);
955 nl_msg_end_nested(request, act_offset);
956 } else {
957 act_offset = nl_msg_start_nested(request, act_index++);
958 nl_msg_put_act_drop(request);
959 nl_msg_put_act_cookie(request, &flower->act_cookie);
960 nl_msg_end_nested(request, act_offset);
961 }
962 }
963 nl_msg_end_nested(request, offset);
964}
965
966static void
967nl_msg_put_masked_value(struct ofpbuf *request, uint16_t type,
968 uint16_t mask_type, const void *data,
969 const void *mask_data, size_t len)
970{
971 if (mask_type != TCA_FLOWER_UNSPEC) {
972 if (is_all_zeros(mask_data, len)) {
973 return;
974 }
975 nl_msg_put_unspec(request, mask_type, mask_data, len);
976 }
977 nl_msg_put_unspec(request, type, data, len);
978}
979
980static void
981nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower)
982{
983 ovs_be32 ipv4_src = flower->tunnel.ipv4.ipv4_src;
984 ovs_be32 ipv4_dst = flower->tunnel.ipv4.ipv4_dst;
985 struct in6_addr *ipv6_src = &flower->tunnel.ipv6.ipv6_src;
986 struct in6_addr *ipv6_dst = &flower->tunnel.ipv6.ipv6_dst;
987 ovs_be16 tp_dst = flower->tunnel.tp_dst;
988 ovs_be32 id = be64_to_be32(flower->tunnel.id);
989
990 nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_KEY_ID, id);
991 if (ipv4_dst) {
992 nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_IPV4_SRC, ipv4_src);
993 nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_IPV4_DST, ipv4_dst);
994 } else if (!is_all_zeros(ipv6_dst, sizeof *ipv6_dst)) {
995 nl_msg_put_in6_addr(request, TCA_FLOWER_KEY_ENC_IPV6_SRC, ipv6_src);
996 nl_msg_put_in6_addr(request, TCA_FLOWER_KEY_ENC_IPV6_DST, ipv6_dst);
997 }
998 nl_msg_put_be16(request, TCA_FLOWER_KEY_ENC_UDP_DST_PORT, tp_dst);
999}
1000
bb170644
PB
1001#define FLOWER_PUT_MASKED_VALUE(member, type) \
1002 nl_msg_put_masked_value(request, type, type##_MASK, &flower->key.member, \
1003 &flower->mask.member, sizeof flower->key.member)
1004
f98e418f
RD
1005static void
1006nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)
1007{
1008 uint16_t host_eth_type = ntohs(flower->key.eth_type);
1009 bool is_vlan = (host_eth_type == ETH_TYPE_VLAN);
1010
1011 if (is_vlan) {
1012 host_eth_type = ntohs(flower->key.encap_eth_type);
1013 }
1014
bb170644
PB
1015 FLOWER_PUT_MASKED_VALUE(dst_mac, TCA_FLOWER_KEY_ETH_DST);
1016 FLOWER_PUT_MASKED_VALUE(src_mac, TCA_FLOWER_KEY_ETH_SRC);
f98e418f
RD
1017
1018 if (host_eth_type == ETH_P_IP || host_eth_type == ETH_P_IPV6) {
1019 if (flower->mask.ip_proto && flower->key.ip_proto) {
1020 nl_msg_put_u8(request, TCA_FLOWER_KEY_IP_PROTO,
1021 flower->key.ip_proto);
1022 }
1023
1024 if (flower->key.ip_proto == IPPROTO_UDP) {
2b1d9fa9
PB
1025 FLOWER_PUT_MASKED_VALUE(udp_src, TCA_FLOWER_KEY_UDP_SRC);
1026 FLOWER_PUT_MASKED_VALUE(udp_dst, TCA_FLOWER_KEY_UDP_DST);
f98e418f 1027 } else if (flower->key.ip_proto == IPPROTO_TCP) {
2b1d9fa9
PB
1028 FLOWER_PUT_MASKED_VALUE(tcp_src, TCA_FLOWER_KEY_TCP_SRC);
1029 FLOWER_PUT_MASKED_VALUE(tcp_dst, TCA_FLOWER_KEY_TCP_DST);
4862b4e5 1030 } else if (flower->key.ip_proto == IPPROTO_SCTP) {
2b1d9fa9
PB
1031 FLOWER_PUT_MASKED_VALUE(sctp_src, TCA_FLOWER_KEY_SCTP_SRC);
1032 FLOWER_PUT_MASKED_VALUE(sctp_dst, TCA_FLOWER_KEY_SCTP_DST);
f98e418f
RD
1033 }
1034 }
1035
1036 if (host_eth_type == ETH_P_IP) {
bb170644
PB
1037 FLOWER_PUT_MASKED_VALUE(ipv4.ipv4_src, TCA_FLOWER_KEY_IPV4_SRC);
1038 FLOWER_PUT_MASKED_VALUE(ipv4.ipv4_dst, TCA_FLOWER_KEY_IPV4_DST);
f98e418f 1039 } else if (host_eth_type == ETH_P_IPV6) {
bb170644
PB
1040 FLOWER_PUT_MASKED_VALUE(ipv6.ipv6_src, TCA_FLOWER_KEY_IPV6_SRC);
1041 FLOWER_PUT_MASKED_VALUE(ipv6.ipv6_dst, TCA_FLOWER_KEY_IPV6_DST);
f98e418f
RD
1042 }
1043
1044 nl_msg_put_be16(request, TCA_FLOWER_KEY_ETH_TYPE, flower->key.eth_type);
1045
1046 if (is_vlan) {
1047 if (flower->key.vlan_id || flower->key.vlan_prio) {
1048 nl_msg_put_u16(request, TCA_FLOWER_KEY_VLAN_ID,
1049 flower->key.vlan_id);
1050 nl_msg_put_u8(request, TCA_FLOWER_KEY_VLAN_PRIO,
1051 flower->key.vlan_prio);
1052 }
1053 if (flower->key.encap_eth_type) {
1054 nl_msg_put_be16(request, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
1055 flower->key.encap_eth_type);
1056 }
1057 }
1058
691d20cb 1059 nl_msg_put_u32(request, TCA_FLOWER_FLAGS, tc_get_tc_cls_policy(tc_policy));
f98e418f
RD
1060
1061 if (flower->tunnel.tunnel) {
1062 nl_msg_put_flower_tunnel(request, flower);
1063 }
1064
1065 nl_msg_put_flower_acts(request, flower);
1066}
1067
1068int
1069tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,
1070 struct tc_flower *flower)
1071{
1072 struct ofpbuf request;
1073 struct tcmsg *tcmsg;
1074 struct ofpbuf *reply;
1075 int error = 0;
1076 size_t basic_offset;
1077 uint16_t eth_type = (OVS_FORCE uint16_t) flower->key.eth_type;
1078
1079 tcmsg = tc_make_request(ifindex, RTM_NEWTFILTER,
1080 NLM_F_CREATE | NLM_F_ECHO, &request);
1081 tcmsg->tcm_parent = TC_INGRESS_PARENT;
1082 tcmsg->tcm_info = tc_make_handle(prio, eth_type);
1083 tcmsg->tcm_handle = handle;
1084
1085 nl_msg_put_string(&request, TCA_KIND, "flower");
1086 basic_offset = nl_msg_start_nested(&request, TCA_OPTIONS);
1087 {
1088 nl_msg_put_flower_options(&request, flower);
1089 }
1090 nl_msg_end_nested(&request, basic_offset);
1091
1092 error = tc_transact(&request, &reply);
1093 if (!error) {
1094 struct tcmsg *tc =
1095 ofpbuf_at_assert(reply, NLMSG_HDRLEN, sizeof *tc);
1096
1097 flower->prio = tc_get_major(tc->tcm_info);
1098 flower->handle = tc->tcm_handle;
1099 ofpbuf_delete(reply);
1100 }
1101
1102 return error;
1103}
691d20cb
PB
1104
1105void
1106tc_set_policy(const char *policy)
1107{
1108 if (!policy) {
1109 return;
1110 }
1111
1112 if (!strcmp(policy, "skip_sw")) {
1113 tc_policy = TC_POLICY_SKIP_SW;
1114 } else if (!strcmp(policy, "skip_hw")) {
1115 tc_policy = TC_POLICY_SKIP_HW;
1116 } else if (!strcmp(policy, "none")) {
1117 tc_policy = TC_POLICY_NONE;
1118 } else {
1119 VLOG_WARN("tc: Invalid policy '%s'", policy);
1120 return;
1121 }
1122
1123 VLOG_INFO("tc: Using policy '%s'", policy);
1124}