The branch main has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=205263ac250aadd84931d2b77475bc931c3afeff
commit 205263ac250aadd84931d2b77475bc931c3afeff Author: Ariel Ehrenberg <aehrenb...@nvidia.com> AuthorDate: 2024-07-30 16:50:40 +0000 Commit: Konstantin Belousov <k...@freebsd.org> CommitDate: 2024-08-20 12:42:13 +0000 mlx5en: support ipsec offload on vlan if Add vlan tag match to RX FS SA and policy rules and report SA lifetime counter on vlan interface in case SA was installed on vlan interface Existing code didn't have the net tag id as part of the FS matching rules. This can cause applying ipsec offload to the wrong interface. This commit add tag id as part of FS matchers and treat tag value 0 as no tag Sponsored by: NVidia networking --- sys/dev/mlx5/mlx5_accel/ipsec.h | 6 ++ sys/dev/mlx5/mlx5_accel/mlx5_ipsec.c | 90 +++++++++++++----- sys/dev/mlx5/mlx5_accel/mlx5_ipsec_fs.c | 157 ++++++++++++++++++++++++-------- 3 files changed, 194 insertions(+), 59 deletions(-) diff --git a/sys/dev/mlx5/mlx5_accel/ipsec.h b/sys/dev/mlx5/mlx5_accel/ipsec.h index 2abd68d9770a..95742c4099f1 100644 --- a/sys/dev/mlx5/mlx5_accel/ipsec.h +++ b/sys/dev/mlx5/mlx5_accel/ipsec.h @@ -37,6 +37,8 @@ #define MLX5E_IPSEC_SADB_RX_BITS 10 #define MLX5_IPSEC_METADATA_MARKER(ipsec_metadata) ((ipsec_metadata >> 31) & 0x1) +#define VLAN_NONE 0xfff + struct mlx5e_priv; struct mlx5e_tx_wqe; struct mlx5e_ipsec_tx; @@ -135,6 +137,7 @@ struct mlx5e_ipsec_rule { struct mlx5_flow_handle *rule; struct mlx5_flow_handle *kspi_rule; struct mlx5_flow_handle *reqid_rule; + struct mlx5_flow_handle *vid_zero_rule; struct mlx5_modify_hdr *modify_hdr; struct mlx5_pkt_reformat *pkt_reformat; struct mlx5_fc *fc; @@ -149,6 +152,7 @@ struct mlx5e_ipsec_esn_state { struct mlx5e_ipsec_sa_entry { struct secasvar *savp; if_t ifp; + if_t ifpo; struct mlx5e_ipsec *ipsec; struct mlx5_accel_esp_xfrm_attrs attrs; struct mlx5e_ipsec_rule ipsec_rule; @@ -158,6 +162,7 @@ struct mlx5e_ipsec_sa_entry { u32 enc_key_id; u16 kspi; /* Stack allocated unique SA identifier */ struct mlx5e_ipsec_esn_state esn_state; + u16 vid; }; struct upspec { @@ -184,6 +189,7 @@ struct mlx5_accel_pol_xfrm_attrs { u8 dir : 2; u32 reqid; u32 prio; + u16 vid; }; struct mlx5e_ipsec_pol_entry { diff --git a/sys/dev/mlx5/mlx5_accel/mlx5_ipsec.c b/sys/dev/mlx5/mlx5_accel/mlx5_ipsec.c index 01d1cb28f86d..a25ed4c1c51f 100644 --- a/sys/dev/mlx5/mlx5_accel/mlx5_ipsec.c +++ b/sys/dev/mlx5/mlx5_accel/mlx5_ipsec.c @@ -97,8 +97,8 @@ mlx5e_ipsec_handle_counters(struct work_struct *_work) bytes += bytes1; #ifdef IPSEC_OFFLOAD - ipsec_accel_drv_sa_lifetime_update(sa_entry->savp, sa_entry->ifp, - sa_entry->kspi, bytes, packets); + ipsec_accel_drv_sa_lifetime_update( + sa_entry->savp, sa_entry->ifpo, sa_entry->kspi, bytes, packets); #endif queue_delayed_work(sa_entry->ipsec->wq, &dwork->dwork, @@ -321,19 +321,23 @@ static int mlx5e_xfrm_validate_state(struct mlx5_core_dev *mdev, } static int -mlx5e_if_sa_newkey_onedir(struct ifnet *ifp, void *sav, int dir, - u_int drv_spi, struct mlx5e_ipsec_sa_entry **privp, - struct mlx5e_ipsec_priv_bothdir *pb) +mlx5e_if_sa_newkey_onedir(struct ifnet *ifp, void *sav, int dir, u_int drv_spi, + struct mlx5e_ipsec_sa_entry **privp, struct mlx5e_ipsec_priv_bothdir *pb, + struct ifnet *ifpo) { struct mlx5e_ipsec_sa_entry *sa_entry = NULL; struct mlx5e_priv *priv = if_getsoftc(ifp); struct mlx5_core_dev *mdev = priv->mdev; struct mlx5e_ipsec *ipsec = priv->ipsec; + u16 vid = VLAN_NONE; int err; if (priv->gone != 0 || ipsec == NULL) return (EOPNOTSUPP); + if (if_gettype(ifpo) == IFT_L2VLAN) + VLAN_TAG(ifpo, &vid); + err = mlx5e_xfrm_validate_state(mdev, sav); if (err) return err; @@ -345,7 +349,9 @@ mlx5e_if_sa_newkey_onedir(struct ifnet *ifp, void *sav, int dir, sa_entry->kspi = drv_spi; sa_entry->savp = sav; sa_entry->ifp = ifp; + sa_entry->ifpo = ifpo; sa_entry->ipsec = ipsec; + sa_entry->vid = vid; mlx5e_ipsec_build_accel_xfrm_attrs(sa_entry, &sa_entry->attrs, dir); @@ -387,22 +393,35 @@ err_xfrm: return err; } +#define GET_TRUNK_IF(vifp, ifp, ept) \ + if (if_gettype(vifp) == IFT_L2VLAN) { \ + NET_EPOCH_ENTER(ept); \ + ifp = VLAN_TRUNKDEV(vifp); \ + NET_EPOCH_EXIT(ept); \ + } else { \ + ifp = vifp; \ + } + static int -mlx5e_if_sa_newkey(struct ifnet *ifp, void *sav, u_int dev_spi, void **privp) +mlx5e_if_sa_newkey(struct ifnet *ifpo, void *sav, u_int dev_spi, void **privp) { struct mlx5e_ipsec_priv_bothdir *pb; + struct epoch_tracker et; + struct ifnet *ifp; int error; + GET_TRUNK_IF(ifpo, ifp, et); + pb = malloc(sizeof(struct mlx5e_ipsec_priv_bothdir), M_DEVBUF, M_WAITOK | M_ZERO); - error = mlx5e_if_sa_newkey_onedir(ifp, sav, IPSEC_DIR_INBOUND, - dev_spi, &pb->priv_in, pb); + error = mlx5e_if_sa_newkey_onedir( + ifp, sav, IPSEC_DIR_INBOUND, dev_spi, &pb->priv_in, pb, ifpo); if (error != 0) { free(pb, M_DEVBUF); return (error); } - error = mlx5e_if_sa_newkey_onedir(ifp, sav, IPSEC_DIR_OUTBOUND, - dev_spi, &pb->priv_out, pb); + error = mlx5e_if_sa_newkey_onedir( + ifp, sav, IPSEC_DIR_OUTBOUND, dev_spi, &pb->priv_out, pb, ifpo); if (error == 0) { *privp = pb; } else { @@ -431,9 +450,13 @@ mlx5e_if_sa_deinstall_onekey(struct ifnet *ifp, u_int dev_spi, void *priv) } static int -mlx5e_if_sa_deinstall(struct ifnet *ifp, u_int dev_spi, void *priv) +mlx5e_if_sa_deinstall(struct ifnet *ifpo, u_int dev_spi, void *priv) { struct mlx5e_ipsec_priv_bothdir pb, *pbp; + struct epoch_tracker et; + struct ifnet *ifp; + + GET_TRUNK_IF(ifpo, ifp, et); pbp = priv; pb = *(struct mlx5e_ipsec_priv_bothdir *)priv; @@ -462,12 +485,16 @@ mlx5e_if_sa_cnt_one(struct ifnet *ifp, void *sa, uint32_t drv_spi, } static int -mlx5e_if_sa_cnt(struct ifnet *ifp, void *sa, uint32_t drv_spi, - void *priv, struct seclifetime *lt) +mlx5e_if_sa_cnt(struct ifnet *ifpo, void *sa, uint32_t drv_spi, void *priv, + struct seclifetime *lt) { struct mlx5e_ipsec_priv_bothdir *pb; u64 packets_in, packets_out; u64 bytes_in, bytes_out; + struct epoch_tracker et; + struct ifnet *ifp; + + GET_TRUNK_IF(ifpo, ifp, et); pb = priv; mlx5e_if_sa_cnt_one(ifp, sa, drv_spi, pb->priv_in, @@ -546,9 +573,9 @@ static int mlx5e_xfrm_validate_policy(struct mlx5_core_dev *mdev, return 0; } -static void mlx5e_ipsec_build_accel_pol_attrs(struct mlx5e_ipsec_pol_entry *pol_entry, - struct mlx5_accel_pol_xfrm_attrs *attrs, - struct inpcb *inp) +static void +mlx5e_ipsec_build_accel_pol_attrs(struct mlx5e_ipsec_pol_entry *pol_entry, + struct mlx5_accel_pol_xfrm_attrs *attrs, struct inpcb *inp, u16 vid) { struct secpolicy *sp = pol_entry->sp; struct secpolicyindex *spidx = &sp->spidx; @@ -592,15 +619,22 @@ static void mlx5e_ipsec_build_accel_pol_attrs(struct mlx5e_ipsec_pol_entry *pol_ attrs->action = IPSEC_POLICY_IPSEC; } attrs->dir = spidx->dir; + attrs->vid = vid; } -static int mlx5e_if_spd_install(struct ifnet *ifp, void *sp, void *inp1, - void **ifdatap) +static int +mlx5e_if_spd_install(struct ifnet *ifpo, void *sp, void *inp1, void **ifdatap) { struct mlx5e_ipsec_pol_entry *pol_entry; struct mlx5e_priv *priv; + struct epoch_tracker et; + u16 vid = VLAN_NONE; + struct ifnet *ifp; int err; + GET_TRUNK_IF(ifpo, ifp, et); + if (if_gettype(ifpo) == IFT_L2VLAN) + VLAN_TAG(ifpo, &vid); priv = if_getsoftc(ifp); if (priv->gone || !priv->ipsec) return (EOPNOTSUPP); @@ -616,7 +650,8 @@ static int mlx5e_if_spd_install(struct ifnet *ifp, void *sp, void *inp1, pol_entry->sp = sp; pol_entry->ipsec = priv->ipsec; - mlx5e_ipsec_build_accel_pol_attrs(pol_entry, &pol_entry->attrs, inp1); + mlx5e_ipsec_build_accel_pol_attrs(pol_entry, &pol_entry->attrs, + inp1, vid); err = mlx5e_accel_ipsec_fs_add_pol(pol_entry); if (err) goto err_pol; @@ -630,11 +665,12 @@ err_pol: return err; } - -static int mlx5e_if_spd_deinstall(struct ifnet *ifp, void *sp, void *ifdata) +static int +mlx5e_if_spd_deinstall(struct ifnet *ifpo, void *sp, void *ifdata) { - struct mlx5e_ipsec_pol_entry *pol_entry = to_ipsec_pol_entry(ifdata); + struct mlx5e_ipsec_pol_entry *pol_entry; + pol_entry = to_ipsec_pol_entry(ifdata); mlx5e_accel_ipsec_fs_del_pol(pol_entry); kfree(pol_entry); return 0; @@ -654,9 +690,17 @@ void mlx5e_ipsec_cleanup(struct mlx5e_priv *priv) } static int -mlx5e_if_ipsec_hwassist(if_t ifnet, void *sav __unused, +mlx5e_if_ipsec_hwassist(if_t ifneto, void *sav __unused, uint32_t drv_spi __unused, void *priv __unused) { + if_t ifnet; + + if (if_gettype(ifneto) == IFT_L2VLAN) { + ifnet = VLAN_TRUNKDEV(ifneto); + } else { + ifnet = ifneto; + } + return (if_gethwassist(ifnet) & (CSUM_TSO | CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_IP6_TSO | CSUM_IP6_TCP | CSUM_IP6_UDP)); } diff --git a/sys/dev/mlx5/mlx5_accel/mlx5_ipsec_fs.c b/sys/dev/mlx5/mlx5_accel/mlx5_ipsec_fs.c index a6a0398f9dca..e348ab1992a5 100644 --- a/sys/dev/mlx5/mlx5_accel/mlx5_ipsec_fs.c +++ b/sys/dev/mlx5/mlx5_accel/mlx5_ipsec_fs.c @@ -185,6 +185,44 @@ static void setup_fte_spi(struct mlx5_flow_spec *spec, u32 spi, bool encap) } } +static void +setup_fte_vid(struct mlx5_flow_spec *spec, u16 vid) +{ + /* virtual lan tag */ + spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS; + + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, + outer_headers.cvlan_tag); + MLX5_SET(fte_match_param, spec->match_value, + outer_headers.cvlan_tag, 1); + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, + outer_headers.first_vid); + MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, + vid); +} + +static void +clear_fte_vid(struct mlx5_flow_spec *spec) +{ + MLX5_SET(fte_match_param, spec->match_criteria, + outer_headers.cvlan_tag, 0); + MLX5_SET(fte_match_param, spec->match_value, + outer_headers.cvlan_tag, 0); + MLX5_SET(fte_match_param, spec->match_criteria, + outer_headers.first_vid, 0); + MLX5_SET(fte_match_param, spec->match_value, + outer_headers.first_vid, 0); +} + +static void +setup_fte_no_vid(struct mlx5_flow_spec *spec) +{ + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, + outer_headers.cvlan_tag); + MLX5_SET(fte_match_param, spec->match_value, + outer_headers.cvlan_tag, 0); +} + static struct mlx5_fs_chains * ipsec_chains_create(struct mlx5_core_dev *mdev, struct mlx5_flow_table *miss_ft, enum mlx5_flow_namespace_type ns, int base_prio, @@ -474,17 +512,6 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry) if (!spec) return -ENOMEM; - if (attrs->family == AF_INET) - setup_fte_addr4(spec, &attrs->saddr.a4, &attrs->daddr.a4); - else - setup_fte_addr6(spec, attrs->saddr.a6, attrs->daddr.a6); - - if (!attrs->encap) - setup_fte_esp(spec); - - setup_fte_spi(spec, attrs->spi, attrs->encap); - setup_fte_no_frags(spec); - if (!attrs->drop) { err = setup_modify_header(mdev, sa_entry->kspi | BIT(31), IPSEC_DIR_INBOUND, &flow_act); @@ -520,15 +547,46 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry) dest[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; dest[1].counter_id = mlx5_fc_id(counter); + if (attrs->family == AF_INET) + setup_fte_addr4(spec, &attrs->saddr.a4, &attrs->daddr.a4); + else + setup_fte_addr6(spec, attrs->saddr.a6, attrs->daddr.a6); + + if (!attrs->encap) + setup_fte_esp(spec); + + setup_fte_spi(spec, attrs->spi, attrs->encap); + setup_fte_no_frags(spec); + + if (sa_entry->vid != VLAN_NONE) + setup_fte_vid(spec, sa_entry->vid); + else + setup_fte_no_vid(spec); + rule = mlx5_add_flow_rules(rx->ft.sa, spec, &flow_act, dest, 2); if (IS_ERR(rule)) { err = PTR_ERR(rule); mlx5_core_err(mdev, "fail to add RX ipsec rule err=%d\n", err); goto err_add_flow; } + ipsec_rule->rule = rule; + + /* Add another rule for zero vid */ + if (sa_entry->vid == VLAN_NONE) { + clear_fte_vid(spec); + setup_fte_vid(spec, 0); + rule = mlx5_add_flow_rules(rx->ft.sa, spec, &flow_act, dest, 2); + if (IS_ERR(rule)) { + err = PTR_ERR(rule); + mlx5_core_err(mdev, + "fail to add RX ipsec zero vid rule err=%d\n", + err); + goto err_add_flow; + } + ipsec_rule->vid_zero_rule = rule; + } kvfree(spec); - ipsec_rule->rule = rule; ipsec_rule->fc = counter; ipsec_rule->modify_hdr = flow_act.modify_hdr; ipsec_rule->pkt_reformat = flow_act.pkt_reformat; @@ -536,10 +594,12 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry) err_add_flow: mlx5_fc_destroy(mdev, counter); + if (ipsec_rule->rule != NULL) + mlx5_del_flow_rules(&ipsec_rule->rule); err_add_cnt: mlx5_packet_reformat_dealloc(mdev, flow_act.pkt_reformat); err_pkt_reformat: - if (flow_act.modify_hdr) + if (flow_act.modify_hdr != NULL) mlx5_modify_header_dealloc(mdev, flow_act.modify_hdr); err_mod_header: kvfree(spec); @@ -1222,8 +1282,6 @@ static int tx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry) switch (attrs->action) { case IPSEC_POLICY_IPSEC: flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; - /*if (!attrs->reqid) - break;*/ err = setup_modify_header(mdev, attrs->reqid, IPSEC_DIR_OUTBOUND, &flow_act); if (err) @@ -1278,7 +1336,7 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry) struct mlx5_flow_spec *spec; struct mlx5_flow_table *ft; struct mlx5e_ipsec_rx *rx; - int err, dstn = 0; + int err, dstn = 0; rx = (attrs->family == AF_INET) ? ipsec->rx_ipv4 : ipsec->rx_ipv6; ft = rx->chains ? ipsec_chains_get_table(rx->chains, attrs->prio) : rx->ft.pol; @@ -1291,14 +1349,6 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry) goto err_alloc; } - if (attrs->family == AF_INET) - setup_fte_addr4(spec, &attrs->saddr.a4, &attrs->daddr.a4); - else - setup_fte_addr6(spec, attrs->saddr.a6, attrs->daddr.a6); - - setup_fte_no_frags(spec); - setup_fte_upper_proto_match(spec, &attrs->upspec); - switch (attrs->action) { case IPSEC_POLICY_IPSEC: flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; @@ -1318,21 +1368,52 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry) dest[dstn].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; dest[dstn].ft = rx->ft.sa; dstn++; - rule = mlx5_add_flow_rules(ft, spec, &flow_act, dest, dstn); - if (IS_ERR(rule)) { - err = PTR_ERR(rule); - mlx5_core_err(mdev, "Fail to add RX IPsec policy rule err=%d\n", err); - goto err_action; - } - kvfree(spec); - pol_entry->ipsec_rule.rule = rule; + if (attrs->family == AF_INET) + setup_fte_addr4(spec, &attrs->saddr.a4, &attrs->daddr.a4); + else + setup_fte_addr6(spec, attrs->saddr.a6, attrs->daddr.a6); + + setup_fte_no_frags(spec); + setup_fte_upper_proto_match(spec, &attrs->upspec); + if (attrs->vid != VLAN_NONE) + setup_fte_vid(spec, attrs->vid); + else + setup_fte_no_vid(spec); + + rule = mlx5_add_flow_rules(ft, spec, &flow_act, dest, dstn); + if (IS_ERR(rule)) { + err = PTR_ERR(rule); + mlx5_core_err(mdev, + "Failed to add RX IPsec policy rule err=%d\n", err); + goto err_action; + } + pol_entry->ipsec_rule.rule = rule; + + /* Add also rule for zero vid */ + if (attrs->vid == VLAN_NONE) { + clear_fte_vid(spec); + setup_fte_vid(spec, 0); + rule = mlx5_add_flow_rules(ft, spec, &flow_act, dest, dstn); + if (IS_ERR(rule)) { + err = PTR_ERR(rule); + mlx5_core_err(mdev, + "Failed to add RX IPsec policy rule err=%d\n", + err); + goto err_action; + } + pol_entry->ipsec_rule.vid_zero_rule = rule; + } + + kvfree(spec); return 0; err_action: - kvfree(spec); + if (pol_entry->ipsec_rule.rule != NULL) + mlx5_del_flow_rules(&pol_entry->ipsec_rule.rule); + kvfree(spec); err_alloc: - if (rx->chains) + if (rx->chains != NULL) ipsec_chains_put_table(rx->chains, attrs->prio); return err; } @@ -1854,7 +1935,9 @@ void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_ipsec_sa_entry *sa_entry) mlx5_del_flow_rules(&ipsec_rule->rule); mlx5_del_flow_rules(&ipsec_rule->kspi_rule); - if (ipsec_rule->reqid_rule) + if (ipsec_rule->vid_zero_rule != NULL) + mlx5_del_flow_rules(&ipsec_rule->vid_zero_rule); + if (ipsec_rule->reqid_rule != NULL) mlx5_del_flow_rules(&ipsec_rule->reqid_rule); mlx5_fc_destroy(mdev, ipsec_rule->fc); mlx5_packet_reformat_dealloc(mdev, ipsec_rule->pkt_reformat); @@ -1863,7 +1946,7 @@ void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_ipsec_sa_entry *sa_entry) return; } - if (ipsec_rule->modify_hdr) + if (ipsec_rule->modify_hdr != NULL) mlx5_modify_header_dealloc(mdev, ipsec_rule->modify_hdr); } @@ -1881,6 +1964,8 @@ void mlx5e_accel_ipsec_fs_del_pol(struct mlx5e_ipsec_pol_entry *pol_entry) struct mlx5_core_dev *mdev = mlx5e_ipsec_pol2dev(pol_entry); mlx5_del_flow_rules(&ipsec_rule->rule); + if (ipsec_rule->vid_zero_rule != NULL) + mlx5_del_flow_rules(&ipsec_rule->vid_zero_rule); if (pol_entry->attrs.dir == IPSEC_DIR_INBOUND) { struct mlx5e_ipsec_rx *rx;