| 1 | #ifndef _NET_FLOW_OFFLOAD_H
|
| 2 | #define _NET_FLOW_OFFLOAD_H
|
| 3 |
|
| 4 | #include <linux/kernel.h>
|
| 5 | #include <linux/list.h>
|
| 6 | #include <linux/netlink.h>
|
| 7 | #include <net/flow_dissector.h>
|
| 8 |
|
| 9 | struct flow_match {
|
| 10 | struct flow_dissector *dissector;
|
| 11 | void *mask;
|
| 12 | void *key;
|
| 13 | };
|
| 14 |
|
| 15 | struct flow_match_meta {
|
| 16 | struct flow_dissector_key_meta *key, *mask;
|
| 17 | };
|
| 18 |
|
| 19 | struct flow_match_basic {
|
| 20 | struct flow_dissector_key_basic *key, *mask;
|
| 21 | };
|
| 22 |
|
| 23 | struct flow_match_control {
|
| 24 | struct flow_dissector_key_control *key, *mask;
|
| 25 | };
|
| 26 |
|
| 27 | struct flow_match_eth_addrs {
|
| 28 | struct flow_dissector_key_eth_addrs *key, *mask;
|
| 29 | };
|
| 30 |
|
| 31 | struct flow_match_vlan {
|
| 32 | struct flow_dissector_key_vlan *key, *mask;
|
| 33 | };
|
| 34 |
|
| 35 | struct flow_match_arp {
|
| 36 | struct flow_dissector_key_arp *key, *mask;
|
| 37 | };
|
| 38 |
|
| 39 | struct flow_match_ipv4_addrs {
|
| 40 | struct flow_dissector_key_ipv4_addrs *key, *mask;
|
| 41 | };
|
| 42 |
|
| 43 | struct flow_match_ipv6_addrs {
|
| 44 | struct flow_dissector_key_ipv6_addrs *key, *mask;
|
| 45 | };
|
| 46 |
|
| 47 | struct flow_match_ip {
|
| 48 | struct flow_dissector_key_ip *key, *mask;
|
| 49 | };
|
| 50 |
|
| 51 | struct flow_match_ports {
|
| 52 | struct flow_dissector_key_ports *key, *mask;
|
| 53 | };
|
| 54 |
|
| 55 | struct flow_match_ports_range {
|
| 56 | struct flow_dissector_key_ports_range *key, *mask;
|
| 57 | };
|
| 58 |
|
| 59 | struct flow_match_icmp {
|
| 60 | struct flow_dissector_key_icmp *key, *mask;
|
| 61 | };
|
| 62 |
|
| 63 | struct flow_match_tcp {
|
| 64 | struct flow_dissector_key_tcp *key, *mask;
|
| 65 | };
|
| 66 |
|
| 67 | struct flow_match_ipsec {
|
| 68 | struct flow_dissector_key_ipsec *key, *mask;
|
| 69 | };
|
| 70 |
|
| 71 | struct flow_match_mpls {
|
| 72 | struct flow_dissector_key_mpls *key, *mask;
|
| 73 | };
|
| 74 |
|
| 75 | struct flow_match_enc_keyid {
|
| 76 | struct flow_dissector_key_keyid *key, *mask;
|
| 77 | };
|
| 78 |
|
| 79 | struct flow_match_enc_opts {
|
| 80 | struct flow_dissector_key_enc_opts *key, *mask;
|
| 81 | };
|
| 82 |
|
| 83 | struct flow_match_ct {
|
| 84 | struct flow_dissector_key_ct *key, *mask;
|
| 85 | };
|
| 86 |
|
| 87 | struct flow_match_pppoe {
|
| 88 | struct flow_dissector_key_pppoe *key, *mask;
|
| 89 | };
|
| 90 |
|
| 91 | struct flow_match_l2tpv3 {
|
| 92 | struct flow_dissector_key_l2tpv3 *key, *mask;
|
| 93 | };
|
| 94 |
|
| 95 | struct flow_rule;
|
| 96 |
|
| 97 | void flow_rule_match_meta(const struct flow_rule *rule,
|
| 98 | struct flow_match_meta *out);
|
| 99 | void flow_rule_match_basic(const struct flow_rule *rule,
|
| 100 | struct flow_match_basic *out);
|
| 101 | void flow_rule_match_control(const struct flow_rule *rule,
|
| 102 | struct flow_match_control *out);
|
| 103 | void flow_rule_match_eth_addrs(const struct flow_rule *rule,
|
| 104 | struct flow_match_eth_addrs *out);
|
| 105 | void flow_rule_match_vlan(const struct flow_rule *rule,
|
| 106 | struct flow_match_vlan *out);
|
| 107 | void flow_rule_match_cvlan(const struct flow_rule *rule,
|
| 108 | struct flow_match_vlan *out);
|
| 109 | void flow_rule_match_arp(const struct flow_rule *rule,
|
| 110 | struct flow_match_arp *out);
|
| 111 | void flow_rule_match_ipv4_addrs(const struct flow_rule *rule,
|
| 112 | struct flow_match_ipv4_addrs *out);
|
| 113 | void flow_rule_match_ipv6_addrs(const struct flow_rule *rule,
|
| 114 | struct flow_match_ipv6_addrs *out);
|
| 115 | void flow_rule_match_ip(const struct flow_rule *rule,
|
| 116 | struct flow_match_ip *out);
|
| 117 | void flow_rule_match_ports(const struct flow_rule *rule,
|
| 118 | struct flow_match_ports *out);
|
| 119 | void flow_rule_match_ports_range(const struct flow_rule *rule,
|
| 120 | struct flow_match_ports_range *out);
|
| 121 | void flow_rule_match_tcp(const struct flow_rule *rule,
|
| 122 | struct flow_match_tcp *out);
|
| 123 | void flow_rule_match_ipsec(const struct flow_rule *rule,
|
| 124 | struct flow_match_ipsec *out);
|
| 125 | void flow_rule_match_icmp(const struct flow_rule *rule,
|
| 126 | struct flow_match_icmp *out);
|
| 127 | void flow_rule_match_mpls(const struct flow_rule *rule,
|
| 128 | struct flow_match_mpls *out);
|
| 129 | void flow_rule_match_enc_control(const struct flow_rule *rule,
|
| 130 | struct flow_match_control *out);
|
| 131 | void flow_rule_match_enc_ipv4_addrs(const struct flow_rule *rule,
|
| 132 | struct flow_match_ipv4_addrs *out);
|
| 133 | void flow_rule_match_enc_ipv6_addrs(const struct flow_rule *rule,
|
| 134 | struct flow_match_ipv6_addrs *out);
|
| 135 | void flow_rule_match_enc_ip(const struct flow_rule *rule,
|
| 136 | struct flow_match_ip *out);
|
| 137 | void flow_rule_match_enc_ports(const struct flow_rule *rule,
|
| 138 | struct flow_match_ports *out);
|
| 139 | void flow_rule_match_enc_keyid(const struct flow_rule *rule,
|
| 140 | struct flow_match_enc_keyid *out);
|
| 141 | void flow_rule_match_enc_opts(const struct flow_rule *rule,
|
| 142 | struct flow_match_enc_opts *out);
|
| 143 | void flow_rule_match_ct(const struct flow_rule *rule,
|
| 144 | struct flow_match_ct *out);
|
| 145 | void flow_rule_match_pppoe(const struct flow_rule *rule,
|
| 146 | struct flow_match_pppoe *out);
|
| 147 | void flow_rule_match_l2tpv3(const struct flow_rule *rule,
|
| 148 | struct flow_match_l2tpv3 *out);
|
| 149 |
|
| 150 | enum flow_action_id {
|
| 151 | FLOW_ACTION_ACCEPT = 0,
|
| 152 | FLOW_ACTION_DROP,
|
| 153 | FLOW_ACTION_TRAP,
|
| 154 | FLOW_ACTION_GOTO,
|
| 155 | FLOW_ACTION_REDIRECT,
|
| 156 | FLOW_ACTION_MIRRED,
|
| 157 | FLOW_ACTION_REDIRECT_INGRESS,
|
| 158 | FLOW_ACTION_MIRRED_INGRESS,
|
| 159 | FLOW_ACTION_VLAN_PUSH,
|
| 160 | FLOW_ACTION_VLAN_POP,
|
| 161 | FLOW_ACTION_VLAN_MANGLE,
|
| 162 | FLOW_ACTION_TUNNEL_ENCAP,
|
| 163 | FLOW_ACTION_TUNNEL_DECAP,
|
| 164 | FLOW_ACTION_MANGLE,
|
| 165 | FLOW_ACTION_ADD,
|
| 166 | FLOW_ACTION_CSUM,
|
| 167 | FLOW_ACTION_MARK,
|
| 168 | FLOW_ACTION_PTYPE,
|
| 169 | FLOW_ACTION_PRIORITY,
|
| 170 | FLOW_ACTION_RX_QUEUE_MAPPING,
|
| 171 | FLOW_ACTION_WAKE,
|
| 172 | FLOW_ACTION_QUEUE,
|
| 173 | FLOW_ACTION_SAMPLE,
|
| 174 | FLOW_ACTION_POLICE,
|
| 175 | FLOW_ACTION_CT,
|
| 176 | FLOW_ACTION_CT_METADATA,
|
| 177 | FLOW_ACTION_MPLS_PUSH,
|
| 178 | FLOW_ACTION_MPLS_POP,
|
| 179 | FLOW_ACTION_MPLS_MANGLE,
|
| 180 | FLOW_ACTION_GATE,
|
| 181 | FLOW_ACTION_PPPOE_PUSH,
|
| 182 | FLOW_ACTION_JUMP,
|
| 183 | FLOW_ACTION_PIPE,
|
| 184 | FLOW_ACTION_VLAN_PUSH_ETH,
|
| 185 | FLOW_ACTION_VLAN_POP_ETH,
|
| 186 | FLOW_ACTION_CONTINUE,
|
| 187 | NUM_FLOW_ACTIONS,
|
| 188 | };
|
| 189 |
|
| 190 | |
| 191 | * tc pedit action. Legacy TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK is mapped to
|
| 192 | * FLOW_ACT_MANGLE_UNSPEC, which is supported by no driver.
|
| 193 |
|
| 194 | enum flow_action_mangle_base {
|
| 195 | FLOW_ACT_MANGLE_UNSPEC = 0,
|
| 196 | FLOW_ACT_MANGLE_HDR_TYPE_ETH,
|
| 197 | FLOW_ACT_MANGLE_HDR_TYPE_IP4,
|
| 198 | FLOW_ACT_MANGLE_HDR_TYPE_IP6,
|
| 199 | FLOW_ACT_MANGLE_HDR_TYPE_TCP,
|
| 200 | FLOW_ACT_MANGLE_HDR_TYPE_UDP,
|
| 201 | };
|
| 202 |
|
| 203 | enum flow_action_hw_stats_bit {
|
| 204 | FLOW_ACTION_HW_STATS_IMMEDIATE_BIT,
|
| 205 | FLOW_ACTION_HW_STATS_DELAYED_BIT,
|
| 206 | FLOW_ACTION_HW_STATS_DISABLED_BIT,
|
| 207 |
|
| 208 | FLOW_ACTION_HW_STATS_NUM_BITS
|
| 209 | };
|
| 210 |
|
| 211 | enum flow_action_hw_stats {
|
| 212 | FLOW_ACTION_HW_STATS_IMMEDIATE =
|
| 213 | BIT(FLOW_ACTION_HW_STATS_IMMEDIATE_BIT),
|
| 214 | FLOW_ACTION_HW_STATS_DELAYED = BIT(FLOW_ACTION_HW_STATS_DELAYED_BIT),
|
| 215 | FLOW_ACTION_HW_STATS_ANY = FLOW_ACTION_HW_STATS_IMMEDIATE |
|
| 216 | FLOW_ACTION_HW_STATS_DELAYED,
|
| 217 | FLOW_ACTION_HW_STATS_DISABLED =
|
| 218 | BIT(FLOW_ACTION_HW_STATS_DISABLED_BIT),
|
| 219 | FLOW_ACTION_HW_STATS_DONT_CARE = BIT(FLOW_ACTION_HW_STATS_NUM_BITS) - 1,
|
| 220 | };
|
| 221 |
|
| 222 | typedef void (*action_destr)(void *priv);
|
| 223 |
|
| 224 | struct flow_action_cookie {
|
| 225 | u32 cookie_len;
|
| 226 | u8 cookie[];
|
| 227 | };
|
| 228 |
|
| 229 | struct flow_action_cookie *flow_action_cookie_create(void *data,
|
| 230 | unsigned int len,
|
| 231 | gfp_t gfp);
|
| 232 | void flow_action_cookie_destroy(struct flow_action_cookie *cookie);
|
| 233 |
|
| 234 | struct flow_action_police {
|
| 235 | u32 burst;
|
| 236 | u64 rate_bytes_ps;
|
| 237 | u64 peakrate_bytes_ps;
|
| 238 | u32 avrate;
|
| 239 | u16 overhead;
|
| 240 | u64 burst_pkt;
|
| 241 | u64 rate_pkt_ps;
|
| 242 | u32 mtu;
|
| 243 | struct {
|
| 244 | enum flow_action_id act_id;
|
| 245 | u32 extval;
|
| 246 | } exceed, notexceed;
|
| 247 | };
|
| 248 |
|
| 249 | struct flow_action_entry {
|
| 250 | enum flow_action_id id;
|
| 251 | u32 hw_index;
|
| 252 | unsigned long cookie;
|
| 253 | u64 miss_cookie;
|
| 254 | enum flow_action_hw_stats hw_stats;
|
| 255 | action_destr destructor;
|
| 256 | void *destructor_priv;
|
| 257 | union {
|
| 258 | u32 chain_index;
|
| 259 | struct net_device *dev;
|
| 260 | struct {
|
| 261 | u16 vid;
|
| 262 | __be16 proto;
|
| 263 | u8 prio;
|
| 264 | } vlan;
|
| 265 | struct {
|
| 266 | unsigned char dst[ETH_ALEN];
|
| 267 | unsigned char src[ETH_ALEN];
|
| 268 | } vlan_push_eth;
|
| 269 | struct {
|
| 270 |
|
| 271 | enum flow_action_mangle_base htype;
|
| 272 | u32 offset;
|
| 273 | u32 mask;
|
| 274 | u32 val;
|
| 275 | } mangle;
|
| 276 | struct ip_tunnel_info *tunnel;
|
| 277 | u32 csum_flags;
|
| 278 | u32 mark;
|
| 279 | u16 ptype;
|
| 280 | u16 rx_queue;
|
| 281 | u32 priority;
|
| 282 | struct {
|
| 283 | u32 ctx;
|
| 284 | u32 index;
|
| 285 | u8 vf;
|
| 286 | } queue;
|
| 287 | struct {
|
| 288 | struct psample_group *psample_group;
|
| 289 | u32 rate;
|
| 290 | u32 trunc_size;
|
| 291 | bool truncate;
|
| 292 | } sample;
|
| 293 | struct flow_action_police police;
|
| 294 | struct {
|
| 295 | int action;
|
| 296 | u16 zone;
|
| 297 | struct nf_flowtable *flow_table;
|
| 298 | } ct;
|
| 299 | struct {
|
| 300 | unsigned long cookie;
|
| 301 | u32 mark;
|
| 302 | u32 labels[4];
|
| 303 | bool orig_dir;
|
| 304 | } ct_metadata;
|
| 305 | struct {
|
| 306 | u32 label;
|
| 307 | __be16 proto;
|
| 308 | u8 tc;
|
| 309 | u8 bos;
|
| 310 | u8 ttl;
|
| 311 | } mpls_push;
|
| 312 | struct {
|
| 313 | __be16 proto;
|
| 314 | } mpls_pop;
|
| 315 | struct {
|
| 316 | u32 label;
|
| 317 | u8 tc;
|
| 318 | u8 bos;
|
| 319 | u8 ttl;
|
| 320 | } mpls_mangle;
|
| 321 | struct {
|
| 322 | s32 prio;
|
| 323 | u64 basetime;
|
| 324 | u64 cycletime;
|
| 325 | u64 cycletimeext;
|
| 326 | u32 num_entries;
|
| 327 | struct action_gate_entry *entries;
|
| 328 | } gate;
|
| 329 | struct {
|
| 330 | u16 sid;
|
| 331 | } pppoe;
|
| 332 | };
|
| 333 | struct flow_action_cookie *user_cookie;
|
| 334 | };
|
| 335 |
|
| 336 | struct flow_action {
|
| 337 | unsigned int num_entries;
|
| 338 | struct flow_action_entry entries[] __counted_by(num_entries);
|
| 339 | };
|
| 340 |
|
| 341 | static inline bool flow_action_has_entries(const struct flow_action *action)
|
| 342 | {
|
| 343 | return action->num_entries;
|
| 344 | }
|
| 345 |
|
| 346 | |
| 347 | * flow_offload_has_one_action() - check if exactly one action is present
|
| 348 | * @action: tc filter flow offload action
|
| 349 | *
|
| 350 | * Return: true if exactly one action is present.
|
| 351 |
|
| 352 | static inline bool flow_offload_has_one_action(const struct flow_action *action)
|
| 353 | {
|
| 354 | return action->num_entries == 1;
|
| 355 | }
|
| 356 |
|
| 357 | static inline bool flow_action_is_last_entry(const struct flow_action *action,
|
| 358 | const struct flow_action_entry *entry)
|
| 359 | {
|
| 360 | return entry == &action->entries[action->num_entries - 1];
|
| 361 | }
|
| 362 |
|
| 363 | #define flow_action_for_each(__i, __act, __actions) \
|
| 364 | for (__i = 0, __act = &(__actions)->entries[0]; \
|
| 365 | __i < (__actions)->num_entries; \
|
| 366 | __act = &(__actions)->entries[++__i])
|
| 367 |
|
| 368 | static inline bool
|
| 369 | flow_action_mixed_hw_stats_check(const struct flow_action *action,
|
| 370 | struct netlink_ext_ack *extack)
|
| 371 | {
|
| 372 | const struct flow_action_entry *action_entry;
|
| 373 | u8 last_hw_stats;
|
| 374 | int i;
|
| 375 |
|
| 376 | if (flow_offload_has_one_action(action))
|
| 377 | return true;
|
| 378 |
|
| 379 | flow_action_for_each(i, action_entry, action) {
|
| 380 | if (i && action_entry->hw_stats != last_hw_stats) {
|
| 381 | NL_SET_ERR_MSG_MOD(extack, "Mixing HW stats types for actions is not supported");
|
| 382 | return false;
|
| 383 | }
|
| 384 | last_hw_stats = action_entry->hw_stats;
|
| 385 | }
|
| 386 | return true;
|
| 387 | }
|
| 388 |
|
| 389 | static inline const struct flow_action_entry *
|
| 390 | flow_action_first_entry_get(const struct flow_action *action)
|
| 391 | {
|
| 392 | WARN_ON(!flow_action_has_entries(action));
|
| 393 | return &action->entries[0];
|
| 394 | }
|
| 395 |
|
| 396 | static inline bool
|
| 397 | __flow_action_hw_stats_check(const struct flow_action *action,
|
| 398 | struct netlink_ext_ack *extack,
|
| 399 | bool check_allow_bit,
|
| 400 | enum flow_action_hw_stats_bit allow_bit)
|
| 401 | {
|
| 402 | const struct flow_action_entry *action_entry;
|
| 403 |
|
| 404 | if (!flow_action_has_entries(action))
|
| 405 | return true;
|
| 406 | if (!flow_action_mixed_hw_stats_check(action, extack))
|
| 407 | return false;
|
| 408 |
|
| 409 | action_entry = flow_action_first_entry_get(action);
|
| 410 |
|
| 411 |
|
| 412 | WARN_ON_ONCE(!action_entry->hw_stats);
|
| 413 |
|
| 414 | if (!check_allow_bit &&
|
| 415 | ~action_entry->hw_stats & FLOW_ACTION_HW_STATS_ANY) {
|
| 416 | NL_SET_ERR_MSG_MOD(extack, "Driver supports only default HW stats type \"any\"");
|
| 417 | return false;
|
| 418 | } else if (check_allow_bit &&
|
| 419 | !(action_entry->hw_stats & BIT(allow_bit))) {
|
| 420 | NL_SET_ERR_MSG_MOD(extack, "Driver does not support selected HW stats type");
|
| 421 | return false;
|
| 422 | }
|
| 423 | return true;
|
| 424 | }
|
| 425 |
|
| 426 | static inline bool
|
| 427 | flow_action_hw_stats_check(const struct flow_action *action,
|
| 428 | struct netlink_ext_ack *extack,
|
| 429 | enum flow_action_hw_stats_bit allow_bit)
|
| 430 | {
|
| 431 | return __flow_action_hw_stats_check(action, extack, true, allow_bit);
|
| 432 | }
|
| 433 |
|
| 434 | static inline bool
|
| 435 | flow_action_basic_hw_stats_check(const struct flow_action *action,
|
| 436 | struct netlink_ext_ack *extack)
|
| 437 | {
|
| 438 | return __flow_action_hw_stats_check(action, extack, false, 0);
|
| 439 | }
|
| 440 |
|
| 441 | struct flow_rule {
|
| 442 | struct flow_match match;
|
| 443 | struct flow_action action;
|
| 444 | };
|
| 445 |
|
| 446 | struct flow_rule *flow_rule_alloc(unsigned int num_actions);
|
| 447 |
|
| 448 | static inline bool flow_rule_match_key(const struct flow_rule *rule,
|
| 449 | enum flow_dissector_key_id key)
|
| 450 | {
|
| 451 | return dissector_uses_key(rule->match.dissector, key);
|
| 452 | }
|
| 453 |
|
| 454 | |
| 455 | * flow_rule_is_supp_control_flags() - check for supported control flags
|
| 456 | * @supp_flags: control flags supported by driver
|
| 457 | * @ctrl_flags: control flags present in rule
|
| 458 | * @extack: The netlink extended ACK for reporting errors.
|
| 459 | *
|
| 460 | * Return: true if only supported control flags are set, false otherwise.
|
| 461 |
|
| 462 | static inline bool flow_rule_is_supp_control_flags(const u32 supp_flags,
|
| 463 | const u32 ctrl_flags,
|
| 464 | struct netlink_ext_ack *extack)
|
| 465 | {
|
| 466 | if (likely((ctrl_flags & ~supp_flags) == 0))
|
| 467 | return true;
|
| 468 |
|
| 469 | NL_SET_ERR_MSG_FMT_MOD(extack,
|
| 470 | "Unsupported match on control.flags %#x",
|
| 471 | ctrl_flags);
|
| 472 |
|
| 473 | return false;
|
| 474 | }
|
| 475 |
|
| 476 | |
| 477 | * flow_rule_is_supp_enc_control_flags() - check for supported control flags
|
| 478 | * @supp_enc_flags: encapsulation control flags supported by driver
|
| 479 | * @enc_ctrl_flags: encapsulation control flags present in rule
|
| 480 | * @extack: The netlink extended ACK for reporting errors.
|
| 481 | *
|
| 482 | * Return: true if only supported control flags are set, false otherwise.
|
| 483 |
|
| 484 | static inline bool flow_rule_is_supp_enc_control_flags(const u32 supp_enc_flags,
|
| 485 | const u32 enc_ctrl_flags,
|
| 486 | struct netlink_ext_ack *extack)
|
| 487 | {
|
| 488 | if (likely((enc_ctrl_flags & ~supp_enc_flags) == 0))
|
| 489 | return true;
|
| 490 |
|
| 491 | NL_SET_ERR_MSG_FMT_MOD(extack,
|
| 492 | "Unsupported match on enc_control.flags %#x",
|
| 493 | enc_ctrl_flags);
|
| 494 |
|
| 495 | return false;
|
| 496 | }
|
| 497 |
|
| 498 | |
| 499 | * flow_rule_has_control_flags() - check for presence of any control flags
|
| 500 | * @ctrl_flags: control flags present in rule
|
| 501 | * @extack: The netlink extended ACK for reporting errors.
|
| 502 | *
|
| 503 | * Return: true if control flags are set, false otherwise.
|
| 504 |
|
| 505 | static inline bool flow_rule_has_control_flags(const u32 ctrl_flags,
|
| 506 | struct netlink_ext_ack *extack)
|
| 507 | {
|
| 508 | return !flow_rule_is_supp_control_flags(0, ctrl_flags, extack);
|
| 509 | }
|
| 510 |
|
| 511 | |
| 512 | * flow_rule_has_enc_control_flags() - check for presence of any control flags
|
| 513 | * @enc_ctrl_flags: encapsulation control flags present in rule
|
| 514 | * @extack: The netlink extended ACK for reporting errors.
|
| 515 | *
|
| 516 | * Return: true if control flags are set, false otherwise.
|
| 517 |
|
| 518 | static inline bool flow_rule_has_enc_control_flags(const u32 enc_ctrl_flags,
|
| 519 | struct netlink_ext_ack *extack)
|
| 520 | {
|
| 521 | return !flow_rule_is_supp_enc_control_flags(0, enc_ctrl_flags, extack);
|
| 522 | }
|
| 523 |
|
| 524 | |
| 525 | * flow_rule_match_has_control_flags() - match and check for any control flags
|
| 526 | * @rule: The flow_rule under evaluation.
|
| 527 | * @extack: The netlink extended ACK for reporting errors.
|
| 528 | *
|
| 529 | * Return: true if control flags are set, false otherwise.
|
| 530 |
|
| 531 | static inline bool flow_rule_match_has_control_flags(const struct flow_rule *rule,
|
| 532 | struct netlink_ext_ack *extack)
|
| 533 | {
|
| 534 | struct flow_match_control match;
|
| 535 |
|
| 536 | if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL))
|
| 537 | return false;
|
| 538 |
|
| 539 | flow_rule_match_control(rule, &match);
|
| 540 |
|
| 541 | return flow_rule_has_control_flags(match.mask->flags, extack);
|
| 542 | }
|
| 543 |
|
| 544 | struct flow_stats {
|
| 545 | u64 pkts;
|
| 546 | u64 bytes;
|
| 547 | u64 drops;
|
| 548 | u64 lastused;
|
| 549 | enum flow_action_hw_stats used_hw_stats;
|
| 550 | bool used_hw_stats_valid;
|
| 551 | };
|
| 552 |
|
| 553 | static inline void flow_stats_update(struct flow_stats *flow_stats,
|
| 554 | u64 bytes, u64 pkts,
|
| 555 | u64 drops, u64 lastused,
|
| 556 | enum flow_action_hw_stats used_hw_stats)
|
| 557 | {
|
| 558 | flow_stats->pkts += pkts;
|
| 559 | flow_stats->bytes += bytes;
|
| 560 | flow_stats->drops += drops;
|
| 561 | flow_stats->lastused = max_t(u64, flow_stats->lastused, lastused);
|
| 562 |
|
| 563 | |
| 564 | * Passing FLOW_ACTION_HW_STATS_ANY is invalid.
|
| 565 |
|
| 566 | WARN_ON(used_hw_stats == FLOW_ACTION_HW_STATS_ANY);
|
| 567 | flow_stats->used_hw_stats |= used_hw_stats;
|
| 568 | flow_stats->used_hw_stats_valid = true;
|
| 569 | }
|
| 570 |
|
| 571 | enum flow_block_command {
|
| 572 | FLOW_BLOCK_BIND,
|
| 573 | FLOW_BLOCK_UNBIND,
|
| 574 | };
|
| 575 |
|
| 576 | enum flow_block_binder_type {
|
| 577 | FLOW_BLOCK_BINDER_TYPE_UNSPEC,
|
| 578 | FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS,
|
| 579 | FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS,
|
| 580 | FLOW_BLOCK_BINDER_TYPE_RED_EARLY_DROP,
|
| 581 | FLOW_BLOCK_BINDER_TYPE_RED_MARK,
|
| 582 | };
|
| 583 |
|
| 584 | struct flow_block {
|
| 585 | struct list_head cb_list;
|
| 586 | };
|
| 587 |
|
| 588 | struct netlink_ext_ack;
|
| 589 |
|
| 590 | struct flow_block_offload {
|
| 591 | enum flow_block_command command;
|
| 592 | enum flow_block_binder_type binder_type;
|
| 593 | bool block_shared;
|
| 594 | bool unlocked_driver_cb;
|
| 595 | struct net *net;
|
| 596 | struct flow_block *block;
|
| 597 | struct list_head cb_list;
|
| 598 | struct list_head *driver_block_list;
|
| 599 | struct netlink_ext_ack *extack;
|
| 600 | struct Qdisc *sch;
|
| 601 | struct list_head *cb_list_head;
|
| 602 | };
|
| 603 |
|
| 604 | enum tc_setup_type;
|
| 605 | typedef int flow_setup_cb_t(enum tc_setup_type type, void *type_data,
|
| 606 | void *cb_priv);
|
| 607 |
|
| 608 | struct flow_block_cb;
|
| 609 |
|
| 610 | struct flow_block_indr {
|
| 611 | struct list_head list;
|
| 612 | struct net_device *dev;
|
| 613 | struct Qdisc *sch;
|
| 614 | enum flow_block_binder_type binder_type;
|
| 615 | void *data;
|
| 616 | void *cb_priv;
|
| 617 | void (*cleanup)(struct flow_block_cb *block_cb);
|
| 618 | };
|
| 619 |
|
| 620 | struct flow_block_cb {
|
| 621 | struct list_head driver_list;
|
| 622 | struct list_head list;
|
| 623 | flow_setup_cb_t *cb;
|
| 624 | void *cb_ident;
|
| 625 | void *cb_priv;
|
| 626 | void (*release)(void *cb_priv);
|
| 627 | struct flow_block_indr indr;
|
| 628 | unsigned int refcnt;
|
| 629 | };
|
| 630 |
|
| 631 | struct flow_block_cb *flow_block_cb_alloc(flow_setup_cb_t *cb,
|
| 632 | void *cb_ident, void *cb_priv,
|
| 633 | void (*release)(void *cb_priv));
|
| 634 | struct flow_block_cb *flow_indr_block_cb_alloc(flow_setup_cb_t *cb,
|
| 635 | void *cb_ident, void *cb_priv,
|
| 636 | void (*release)(void *cb_priv),
|
| 637 | struct flow_block_offload *bo,
|
| 638 | struct net_device *dev,
|
| 639 | struct Qdisc *sch, void *data,
|
| 640 | void *indr_cb_priv,
|
| 641 | void (*cleanup)(struct flow_block_cb *block_cb));
|
| 642 | void flow_block_cb_free(struct flow_block_cb *block_cb);
|
| 643 |
|
| 644 | struct flow_block_cb *flow_block_cb_lookup(struct flow_block *block,
|
| 645 | flow_setup_cb_t *cb, void *cb_ident);
|
| 646 |
|
| 647 | void *flow_block_cb_priv(struct flow_block_cb *block_cb);
|
| 648 | void flow_block_cb_incref(struct flow_block_cb *block_cb);
|
| 649 | unsigned int flow_block_cb_decref(struct flow_block_cb *block_cb);
|
| 650 |
|
| 651 | static inline void flow_block_cb_add(struct flow_block_cb *block_cb,
|
| 652 | struct flow_block_offload *offload)
|
| 653 | {
|
| 654 | list_add_tail(&block_cb->list, &offload->cb_list);
|
| 655 | }
|
| 656 |
|
| 657 | static inline void flow_block_cb_remove(struct flow_block_cb *block_cb,
|
| 658 | struct flow_block_offload *offload)
|
| 659 | {
|
| 660 | list_move(&block_cb->list, &offload->cb_list);
|
| 661 | }
|
| 662 |
|
| 663 | static inline void flow_indr_block_cb_remove(struct flow_block_cb *block_cb,
|
| 664 | struct flow_block_offload *offload)
|
| 665 | {
|
| 666 | list_del(&block_cb->indr.list);
|
| 667 | list_move(&block_cb->list, &offload->cb_list);
|
| 668 | }
|
| 669 |
|
| 670 | bool flow_block_cb_is_busy(flow_setup_cb_t *cb, void *cb_ident,
|
| 671 | struct list_head *driver_block_list);
|
| 672 |
|
| 673 | int flow_block_cb_setup_simple(struct flow_block_offload *f,
|
| 674 | struct list_head *driver_list,
|
| 675 | flow_setup_cb_t *cb,
|
| 676 | void *cb_ident, void *cb_priv, bool ingress_only);
|
| 677 |
|
| 678 | enum flow_cls_command {
|
| 679 | FLOW_CLS_REPLACE,
|
| 680 | FLOW_CLS_DESTROY,
|
| 681 | FLOW_CLS_STATS,
|
| 682 | FLOW_CLS_TMPLT_CREATE,
|
| 683 | FLOW_CLS_TMPLT_DESTROY,
|
| 684 | };
|
| 685 |
|
| 686 | struct flow_cls_common_offload {
|
| 687 | u32 chain_index;
|
| 688 | __be16 protocol;
|
| 689 | u32 prio;
|
| 690 | bool skip_sw;
|
| 691 | struct netlink_ext_ack *extack;
|
| 692 | };
|
| 693 |
|
| 694 | struct flow_cls_offload {
|
| 695 | struct flow_cls_common_offload common;
|
| 696 | enum flow_cls_command command;
|
| 697 | bool use_act_stats;
|
| 698 | unsigned long cookie;
|
| 699 | struct flow_rule *rule;
|
| 700 | struct flow_stats stats;
|
| 701 | u32 classid;
|
| 702 | };
|
| 703 |
|
| 704 | enum offload_act_command {
|
| 705 | FLOW_ACT_REPLACE,
|
| 706 | FLOW_ACT_DESTROY,
|
| 707 | FLOW_ACT_STATS,
|
| 708 | };
|
| 709 |
|
| 710 | struct flow_offload_action {
|
| 711 | struct netlink_ext_ack *extack;
|
| 712 | enum offload_act_command command;
|
| 713 | enum flow_action_id id;
|
| 714 | u32 index;
|
| 715 | unsigned long cookie;
|
| 716 | struct flow_stats stats;
|
| 717 | struct flow_action action;
|
| 718 | };
|
| 719 |
|
| 720 | struct flow_offload_action *offload_action_alloc(unsigned int num_actions);
|
| 721 |
|
| 722 | static inline struct flow_rule *
|
| 723 | flow_cls_offload_flow_rule(const struct flow_cls_offload *flow_cmd)
|
| 724 | {
|
| 725 | return flow_cmd->rule;
|
| 726 | }
|
| 727 |
|
| 728 | static inline void flow_block_init(struct flow_block *flow_block)
|
| 729 | {
|
| 730 | INIT_LIST_HEAD(&flow_block->cb_list);
|
| 731 | }
|
| 732 |
|
| 733 | typedef int flow_indr_block_bind_cb_t(struct net_device *dev, struct Qdisc *sch, void *cb_priv,
|
| 734 | enum tc_setup_type type, void *type_data,
|
| 735 | void *data,
|
| 736 | void (*cleanup)(struct flow_block_cb *block_cb));
|
| 737 |
|
| 738 | int flow_indr_dev_register(flow_indr_block_bind_cb_t *cb, void *cb_priv);
|
| 739 | void flow_indr_dev_unregister(flow_indr_block_bind_cb_t *cb, void *cb_priv,
|
| 740 | void (*release)(void *cb_priv));
|
| 741 | int flow_indr_dev_setup_offload(struct net_device *dev, struct Qdisc *sch,
|
| 742 | enum tc_setup_type type, void *data,
|
| 743 | struct flow_block_offload *bo,
|
| 744 | void (*cleanup)(struct flow_block_cb *block_cb));
|
| 745 | bool flow_indr_dev_exists(void);
|
| 746 |
|
| 747 | #endif
|