1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /* Microsemi Ocelot Switch driver
3 * Copyright (c) 2019 Microsemi Corporation
6 #include <net/pkt_cls.h>
7 #include <net/tc_act/tc_gact.h>
9 #include "ocelot_ace.h"
11 static int ocelot_flower_parse_action(struct flow_cls_offload
*f
,
12 struct ocelot_ace_rule
*ace
)
14 const struct flow_action_entry
*a
;
19 if (!flow_offload_has_one_action(&f
->rule
->action
))
22 if (!flow_action_basic_hw_stats_check(&f
->rule
->action
,
26 flow_action_for_each(i
, a
, &f
->rule
->action
) {
28 case FLOW_ACTION_DROP
:
29 ace
->action
= OCELOT_ACL_ACTION_DROP
;
31 case FLOW_ACTION_TRAP
:
32 ace
->action
= OCELOT_ACL_ACTION_TRAP
;
34 case FLOW_ACTION_POLICE
:
35 ace
->action
= OCELOT_ACL_ACTION_POLICE
;
36 rate
= a
->police
.rate_bytes_ps
;
37 ace
->pol
.rate
= div_u64(rate
, 1000) * 8;
38 burst
= rate
* PSCHED_NS2TICKS(a
->police
.burst
);
39 ace
->pol
.burst
= div_u64(burst
, PSCHED_TICKS_PER_SEC
);
49 static int ocelot_flower_parse(struct flow_cls_offload
*f
,
50 struct ocelot_ace_rule
*ace
)
52 struct flow_rule
*rule
= flow_cls_offload_flow_rule(f
);
53 struct flow_dissector
*dissector
= rule
->match
.dissector
;
55 if (dissector
->used_keys
&
56 ~(BIT(FLOW_DISSECTOR_KEY_CONTROL
) |
57 BIT(FLOW_DISSECTOR_KEY_BASIC
) |
58 BIT(FLOW_DISSECTOR_KEY_PORTS
) |
59 BIT(FLOW_DISSECTOR_KEY_VLAN
) |
60 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS
) |
61 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS
) |
62 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS
))) {
66 if (flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_CONTROL
)) {
67 struct flow_match_control match
;
69 flow_rule_match_control(rule
, &match
);
72 if (flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_ETH_ADDRS
)) {
73 struct flow_match_eth_addrs match
;
74 u16 proto
= ntohs(f
->common
.protocol
);
76 /* The hw support mac matches only for MAC_ETYPE key,
77 * therefore if other matches(port, tcp flags, etc) are added
80 if ((dissector
->used_keys
&
81 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS
) |
82 BIT(FLOW_DISSECTOR_KEY_BASIC
) |
83 BIT(FLOW_DISSECTOR_KEY_CONTROL
))) !=
84 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS
) |
85 BIT(FLOW_DISSECTOR_KEY_BASIC
) |
86 BIT(FLOW_DISSECTOR_KEY_CONTROL
)))
89 if (proto
== ETH_P_IP
||
90 proto
== ETH_P_IPV6
||
94 flow_rule_match_eth_addrs(rule
, &match
);
95 ace
->type
= OCELOT_ACE_TYPE_ETYPE
;
96 ether_addr_copy(ace
->frame
.etype
.dmac
.value
,
98 ether_addr_copy(ace
->frame
.etype
.smac
.value
,
100 ether_addr_copy(ace
->frame
.etype
.dmac
.mask
,
102 ether_addr_copy(ace
->frame
.etype
.smac
.mask
,
104 goto finished_key_parsing
;
107 if (flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_BASIC
)) {
108 struct flow_match_basic match
;
110 flow_rule_match_basic(rule
, &match
);
111 if (ntohs(match
.key
->n_proto
) == ETH_P_IP
) {
112 ace
->type
= OCELOT_ACE_TYPE_IPV4
;
113 ace
->frame
.ipv4
.proto
.value
[0] =
115 ace
->frame
.ipv4
.proto
.mask
[0] =
116 match
.mask
->ip_proto
;
118 if (ntohs(match
.key
->n_proto
) == ETH_P_IPV6
) {
119 ace
->type
= OCELOT_ACE_TYPE_IPV6
;
120 ace
->frame
.ipv6
.proto
.value
[0] =
122 ace
->frame
.ipv6
.proto
.mask
[0] =
123 match
.mask
->ip_proto
;
127 if (flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_IPV4_ADDRS
) &&
128 ntohs(f
->common
.protocol
) == ETH_P_IP
) {
129 struct flow_match_ipv4_addrs match
;
132 flow_rule_match_ipv4_addrs(rule
, &match
);
133 tmp
= &ace
->frame
.ipv4
.sip
.value
.addr
[0];
134 memcpy(tmp
, &match
.key
->src
, 4);
136 tmp
= &ace
->frame
.ipv4
.sip
.mask
.addr
[0];
137 memcpy(tmp
, &match
.mask
->src
, 4);
139 tmp
= &ace
->frame
.ipv4
.dip
.value
.addr
[0];
140 memcpy(tmp
, &match
.key
->dst
, 4);
142 tmp
= &ace
->frame
.ipv4
.dip
.mask
.addr
[0];
143 memcpy(tmp
, &match
.mask
->dst
, 4);
146 if (flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_IPV6_ADDRS
) &&
147 ntohs(f
->common
.protocol
) == ETH_P_IPV6
) {
151 if (flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_PORTS
)) {
152 struct flow_match_ports match
;
154 flow_rule_match_ports(rule
, &match
);
155 ace
->frame
.ipv4
.sport
.value
= ntohs(match
.key
->src
);
156 ace
->frame
.ipv4
.sport
.mask
= ntohs(match
.mask
->src
);
157 ace
->frame
.ipv4
.dport
.value
= ntohs(match
.key
->dst
);
158 ace
->frame
.ipv4
.dport
.mask
= ntohs(match
.mask
->dst
);
161 if (flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_VLAN
)) {
162 struct flow_match_vlan match
;
164 flow_rule_match_vlan(rule
, &match
);
165 ace
->type
= OCELOT_ACE_TYPE_ANY
;
166 ace
->vlan
.vid
.value
= match
.key
->vlan_id
;
167 ace
->vlan
.vid
.mask
= match
.mask
->vlan_id
;
168 ace
->vlan
.pcp
.value
[0] = match
.key
->vlan_priority
;
169 ace
->vlan
.pcp
.mask
[0] = match
.mask
->vlan_priority
;
172 finished_key_parsing
:
173 ace
->prio
= f
->common
.prio
;
175 return ocelot_flower_parse_action(f
, ace
);
179 struct ocelot_ace_rule
*ocelot_ace_rule_create(struct ocelot
*ocelot
, int port
,
180 struct flow_cls_offload
*f
)
182 struct ocelot_ace_rule
*ace
;
184 ace
= kzalloc(sizeof(*ace
), GFP_KERNEL
);
188 ace
->ingress_port_mask
= BIT(port
);
192 int ocelot_cls_flower_replace(struct ocelot
*ocelot
, int port
,
193 struct flow_cls_offload
*f
, bool ingress
)
195 struct ocelot_ace_rule
*ace
;
198 ace
= ocelot_ace_rule_create(ocelot
, port
, f
);
202 ret
= ocelot_flower_parse(f
, ace
);
208 return ocelot_ace_rule_offload_add(ocelot
, ace
);
210 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace
);
212 int ocelot_cls_flower_destroy(struct ocelot
*ocelot
, int port
,
213 struct flow_cls_offload
*f
, bool ingress
)
215 struct ocelot_ace_rule ace
;
217 ace
.prio
= f
->common
.prio
;
220 return ocelot_ace_rule_offload_del(ocelot
, &ace
);
222 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy
);
224 int ocelot_cls_flower_stats(struct ocelot
*ocelot
, int port
,
225 struct flow_cls_offload
*f
, bool ingress
)
227 struct ocelot_ace_rule ace
;
230 ace
.prio
= f
->common
.prio
;
232 ret
= ocelot_ace_rule_stats_update(ocelot
, &ace
);
236 flow_stats_update(&f
->stats
, 0x0, ace
.stats
.pkts
, 0x0,
237 FLOW_ACTION_HW_STATS_IMMEDIATE
);
240 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats
);
242 int ocelot_setup_tc_cls_flower(struct ocelot_port_private
*priv
,
243 struct flow_cls_offload
*f
,
246 struct ocelot
*ocelot
= priv
->port
.ocelot
;
247 int port
= priv
->chip_port
;
252 switch (f
->command
) {
253 case FLOW_CLS_REPLACE
:
254 return ocelot_cls_flower_replace(ocelot
, port
, f
, ingress
);
255 case FLOW_CLS_DESTROY
:
256 return ocelot_cls_flower_destroy(ocelot
, port
, f
, ingress
);
258 return ocelot_cls_flower_stats(ocelot
, port
, f
, ingress
);