// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2023, Advanced Micro Devices, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, incorporated herein by reference.
*/
netif_err(efx, drv, efx->net_dev, "tc ct_entry %lx still present at teardown\n",
conn->cookie);
/* We can release the counter, but we can't remove the CT itself * from hardware because the table meta is already gone.
*/
efx_tc_flower_release_counter(efx, conn->cnt);
kfree(conn);
}
int efx_tc_init_conntrack(struct efx_nic *efx)
{ int rc;
/* Only call this in init failure teardown. * Normal exit should fini instead as there may be entries in the table.
*/ void efx_tc_destroy_conntrack(struct efx_nic *efx)
{
rhashtable_destroy(&efx->tc->ct_ht);
rhashtable_destroy(&efx->tc->ct_zone_ht);
}
flow_rule_match_ipv4_addrs(fr, &fm); if (!IS_ALL_ONES(fm.mask->src)) {
netif_dbg(efx, drv, efx->net_dev, "Conntrack ipv4.src is not exact-match; mask %08x\n",
ntohl(fm.mask->src)); return -EOPNOTSUPP;
}
conn->src_ip = fm.key->src; if (!IS_ALL_ONES(fm.mask->dst)) {
netif_dbg(efx, drv, efx->net_dev, "Conntrack ipv4.dst is not exact-match; mask %08x\n",
ntohl(fm.mask->dst)); return -EOPNOTSUPP;
}
conn->dst_ip = fm.key->dst;
} elseif (ipv == 6 && flow_rule_match_key(fr, FLOW_DISSECTOR_KEY_IPV6_ADDRS)) { struct flow_match_ipv6_addrs fm;
flow_rule_match_ipv6_addrs(fr, &fm); if (!efx_ipv6_addr_all_ones(&fm.mask->src)) {
netif_dbg(efx, drv, efx->net_dev, "Conntrack ipv6.src is not exact-match; mask %pI6\n",
&fm.mask->src); return -EOPNOTSUPP;
}
conn->src_ip6 = fm.key->src; if (!efx_ipv6_addr_all_ones(&fm.mask->dst)) {
netif_dbg(efx, drv, efx->net_dev, "Conntrack ipv6.dst is not exact-match; mask %pI6\n",
&fm.mask->dst); return -EOPNOTSUPP;
}
conn->dst_ip6 = fm.key->dst;
} else {
netif_dbg(efx, drv, efx->net_dev, "Conntrack missing IPv%u addrs\n", ipv); return -EOPNOTSUPP;
}
if (flow_rule_match_key(fr, FLOW_DISSECTOR_KEY_PORTS)) { struct flow_match_ports fm;
flow_rule_match_ports(fr, &fm); if (!IS_ALL_ONES(fm.mask->src)) {
netif_dbg(efx, drv, efx->net_dev, "Conntrack ports.src is not exact-match; mask %04x\n",
ntohs(fm.mask->src)); return -EOPNOTSUPP;
}
conn->l4_sport = fm.key->src; if (!IS_ALL_ONES(fm.mask->dst)) {
netif_dbg(efx, drv, efx->net_dev, "Conntrack ports.dst is not exact-match; mask %04x\n",
ntohs(fm.mask->dst)); return -EOPNOTSUPP;
}
conn->l4_dport = fm.key->dst;
} else {
netif_dbg(efx, drv, efx->net_dev, "Conntrack missing L4 ports\n"); return -EOPNOTSUPP;
}
if (flow_rule_match_key(fr, FLOW_DISSECTOR_KEY_TCP)) {
__be16 tcp_interesting_flags; struct flow_match_tcp fm;
if (!tcp) {
netif_dbg(efx, drv, efx->net_dev, "Conntrack matching on TCP keys but ipproto is not tcp\n"); return -EOPNOTSUPP;
}
flow_rule_match_tcp(fr, &fm);
tcp_interesting_flags = EFX_NF_TCP_FLAG(SYN) |
EFX_NF_TCP_FLAG(RST) |
EFX_NF_TCP_FLAG(FIN); /* If any of the tcp_interesting_flags is set, we always * inhibit CT lookup in LHS (so SW can update CT table).
*/ if (fm.key->flags & tcp_interesting_flags) {
netif_dbg(efx, drv, efx->net_dev, "Unsupported conntrack tcp.flags %04x/%04x\n",
ntohs(fm.key->flags), ntohs(fm.mask->flags)); return -EOPNOTSUPP;
} /* Other TCP flags cannot be filtered at CT */ if (fm.mask->flags & ~tcp_interesting_flags) {
netif_dbg(efx, drv, efx->net_dev, "Unsupported conntrack tcp.flags %04x/%04x\n",
ntohs(fm.key->flags), ntohs(fm.mask->flags)); return -EOPNOTSUPP;
}
}
return 0;
}
/** * struct efx_tc_ct_mangler_state - tracks which fields have been pedited * * @ipv4: IP source or destination addr has been set * @tcpudp: TCP/UDP source or destination port has been set
*/ struct efx_tc_ct_mangler_state {
u8 ipv4:1;
u8 tcpudp:1;
};
staticint efx_tc_ct_mangle(struct efx_nic *efx, struct efx_tc_ct_entry *conn, conststruct flow_action_entry *fa, struct efx_tc_ct_mangler_state *mung)
{ /* Is this the first mangle we've processed for this rule? */ bool first = !(mung->ipv4 || mung->tcpudp); bool dnat = false;
switch (fa->mangle.htype) { case FLOW_ACT_MANGLE_HDR_TYPE_IP4: switch (fa->mangle.offset) { case offsetof(struct iphdr, daddr):
dnat = true;
fallthrough; case offsetof(struct iphdr, saddr): if (fa->mangle.mask) return -EOPNOTSUPP;
conn->nat_ip = htonl(fa->mangle.val);
mung->ipv4 = 1; break; default: return -EOPNOTSUPP;
} break; case FLOW_ACT_MANGLE_HDR_TYPE_TCP: case FLOW_ACT_MANGLE_HDR_TYPE_UDP: /* Both struct tcphdr and struct udphdr start with * __be16 source; * __be16 dest; * so we can use the same code for both.
*/ switch (fa->mangle.offset) { case offsetof(struct tcphdr, dest):
BUILD_BUG_ON(offsetof(struct tcphdr, dest) !=
offsetof(struct udphdr, dest));
dnat = true;
fallthrough; case offsetof(struct tcphdr, source):
BUILD_BUG_ON(offsetof(struct tcphdr, source) !=
offsetof(struct udphdr, source)); if (~fa->mangle.mask != 0xffff) return -EOPNOTSUPP;
conn->l4_natport = htons(fa->mangle.val);
mung->tcpudp = 1; break; default: return -EOPNOTSUPP;
} break; default: return -EOPNOTSUPP;
} /* first mangle tells us whether this is SNAT or DNAT; * subsequent mangles must match that
*/ if (first)
conn->dnat = dnat; elseif (conn->dnat != dnat) return -EOPNOTSUPP; return 0;
}
rc = efx_mae_insert_ct(efx, conn); if (rc) {
netif_dbg(efx, drv, efx->net_dev, "Failed to insert conntrack, %d\n", rc); goto release;
}
mutex_lock(&ct_zone->mutex);
list_add_tail(&conn->list, &ct_zone->cts);
mutex_unlock(&ct_zone->mutex); return 0;
release: if (conn->cnt)
efx_tc_flower_release_counter(efx, conn->cnt); if (!old)
rhashtable_remove_fast(&efx->tc->ct_ht, &conn->linkage,
efx_tc_ct_ht_params);
kfree(conn); return rc;
}
/* Caller must follow with efx_tc_ct_remove_finish() after RCU grace period! */ staticvoid efx_tc_ct_remove(struct efx_nic *efx, struct efx_tc_ct_entry *conn)
{ int rc;
/* Remove it from HW */
rc = efx_mae_remove_ct(efx, conn); /* Delete it from SW */
rhashtable_remove_fast(&efx->tc->ct_ht, &conn->linkage,
efx_tc_ct_ht_params); if (rc) {
netif_err(efx, drv, efx->net_dev, "Failed to remove conntrack %lx from hw, rc %d\n",
conn->cookie, rc);
} else {
netif_dbg(efx, drv, efx->net_dev, "Removed conntrack %lx\n",
conn->cookie);
}
}
staticvoid efx_tc_ct_remove_finish(struct efx_nic *efx, struct efx_tc_ct_entry *conn)
{ /* Remove related CT counter. This is delayed after the conn object we * are working with has been successfully removed. This protects the * counter from being used-after-free inside efx_tc_ct_stats.
*/
efx_tc_flower_release_counter(efx, conn->cnt);
kfree(conn);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.