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