2023-09-13 20:24:59

by Radu Pirea (NXP OSS)

[permalink] [raw]
Subject: [RFC net-next v4 0/7] Add MACsec support for TJA11XX C45 PHYs

This is the MACsec support for TJA11XX PHYs. The MACsec block encrypts
the ethernet frames on the fly and has no buffering. This operation will
grow the frames by 32 bytes. If the frames are sent back to back, the
MACsec block will not have enough room to insert the SecTAG and the ICV
and the frames will be dropped.

To mitigate this, the PHY can parse a specific ethertype with some
padding bytes and replace them with the SecTAG and ICV. These padding
bytes might be dummy or might contain information about TX SC that must
be used to encrypt the frame.

Radu P.

Radu Pirea (NXP OSS) (7):
net: macsec: move sci_to_cpu to macsec header
net: macsec: documentation for macsec_context and macsec_ops
net: macsec: indicate next pn update when offloading
net: macsec: introduce mdo_insert_tx_tag
net: phy: nxp-c45-tja11xx: add MACsec support
net: phy: nxp-c45-tja11xx: add MACsec statistics
net: phy: nxp-c45-tja11xx: implement mdo_insert_tx_tag

MAINTAINERS | 2 +-
drivers/net/macsec.c | 94 +-
drivers/net/netdevsim/macsec.c | 5 -
drivers/net/phy/Kconfig | 2 +-
drivers/net/phy/Makefile | 6 +-
drivers/net/phy/nxp-c45-tja11xx-macsec.c | 1723 ++++++++++++++++++++++
drivers/net/phy/nxp-c45-tja11xx.c | 75 +-
drivers/net/phy/nxp-c45-tja11xx.h | 62 +
include/net/macsec.h | 55 +
9 files changed, 1986 insertions(+), 38 deletions(-)
create mode 100644 drivers/net/phy/nxp-c45-tja11xx-macsec.c
create mode 100644 drivers/net/phy/nxp-c45-tja11xx.h

--
2.34.1


2023-09-13 23:43:09

by Radu Pirea (NXP OSS)

[permalink] [raw]
Subject: [RFC net-next v4 7/7] net: phy: nxp-c45-tja11xx: implement mdo_insert_tx_tag

Implement mdo_insert_tx_tag to insert the TLV header in the ethernet
frame.

Signed-off-by: Radu Pirea (NXP OSS) <[email protected]>
---
Changes in V4:
- removed macsec_extscs parameter

Changes in V3:
- extscs parameter renamed to macsec_extscs and improved description

Changes in V2:
- added extscs parameter to choose the TX SC selection mechanism between
and MAC SA based selection and TLV header based selection

drivers/net/phy/nxp-c45-tja11xx-macsec.c | 44 ++++++++++++++++++++++++
1 file changed, 44 insertions(+)

diff --git a/drivers/net/phy/nxp-c45-tja11xx-macsec.c b/drivers/net/phy/nxp-c45-tja11xx-macsec.c
index 3634b6cedf24..a9f587d5fbca 100644
--- a/drivers/net/phy/nxp-c45-tja11xx-macsec.c
+++ b/drivers/net/phy/nxp-c45-tja11xx-macsec.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/phy.h>
#include <linux/processor.h>
+#include <net/dst_metadata.h>
#include <net/macsec.h>

#include "nxp-c45-tja11xx.h"
@@ -118,6 +119,8 @@
#define ADPTR_CNTRL 0x0F00
#define ADPTR_CNTRL_CONFIG_EN BIT(14)
#define ADPTR_CNTRL_ADPTR_EN BIT(12)
+#define ADPTR_TX_TAG_CNTRL 0x0F0C
+#define ADPTR_TX_TAG_CNTRL_ENA BIT(31)

#define TX_SC_FLT_BASE 0x800
#define TX_SC_FLT_SIZE 0x10
@@ -166,6 +169,14 @@
#define MACSEC_INPBTS 0x0638
#define MACSEC_IPSNFS 0x063C

+#define TJA11XX_TLV_TX_NEEDED_HEADROOM (32)
+#define TJA11XX_TLV_NEEDED_TAILROOM (0)
+
+#define MACSEC_TLV_CP BIT(0)
+#define MACSEC_TLV_SC_ID_OFF (2)
+
+#define ETH_P_TJA11XX_TLV (0x4e58)
+
enum nxp_c45_sa_type {
TX_SA,
RX_SA,
@@ -1537,6 +1548,31 @@ static int nxp_c45_mdo_get_rx_sa_stats(struct macsec_context *ctx)
return 0;
}

+struct tja11xx_tlv_header {
+ struct ethhdr eth;
+ u8 subtype;
+ u8 len;
+ u8 payload[28];
+};
+
+static int nxp_c45_mdo_insert_tx_tag(struct phy_device *phydev,
+ struct sk_buff *skb)
+{
+ struct tja11xx_tlv_header *tlv;
+ struct ethhdr *eth;
+
+ eth = eth_hdr(skb);
+ tlv = skb_push(skb, TJA11XX_TLV_TX_NEEDED_HEADROOM);
+ memmove(tlv, eth, sizeof(*eth));
+ skb_reset_mac_header(skb);
+ tlv->eth.h_proto = htons(ETH_P_TJA11XX_TLV);
+ tlv->subtype = 1;
+ tlv->len = sizeof(tlv->payload);
+ memset(tlv->payload, 0, sizeof(tlv->payload));
+
+ return 0;
+}
+
static const struct macsec_ops nxp_c45_macsec_ops = {
.mdo_dev_open = nxp_c45_mdo_dev_open,
.mdo_dev_stop = nxp_c45_mdo_dev_stop,
@@ -1557,6 +1593,9 @@ static const struct macsec_ops nxp_c45_macsec_ops = {
.mdo_get_tx_sa_stats = nxp_c45_mdo_get_tx_sa_stats,
.mdo_get_rx_sc_stats = nxp_c45_mdo_get_rx_sc_stats,
.mdo_get_rx_sa_stats = nxp_c45_mdo_get_rx_sa_stats,
+ .mdo_insert_tx_tag = nxp_c45_mdo_insert_tx_tag,
+ .needed_headroom = TJA11XX_TLV_TX_NEEDED_HEADROOM,
+ .needed_tailroom = TJA11XX_TLV_NEEDED_TAILROOM,
};

int nxp_c45_macsec_config_init(struct phy_device *phydev)
@@ -1577,6 +1616,11 @@ int nxp_c45_macsec_config_init(struct phy_device *phydev)
if (ret)
return ret;

+ ret = nxp_c45_macsec_write(phydev, ADPTR_TX_TAG_CNTRL,
+ ADPTR_TX_TAG_CNTRL_ENA);
+ if (ret)
+ return ret;
+
ret = nxp_c45_macsec_write(phydev, ADPTR_CNTRL, ADPTR_CNTRL_ADPTR_EN);
if (ret)
return ret;
--
2.34.1

2023-09-14 01:13:30

by Radu Pirea (NXP OSS)

[permalink] [raw]
Subject: [RFC net-next v4 4/7] net: macsec: introduce mdo_insert_tx_tag

Offloading MACsec in PHYs requires inserting the SecTAG and the ICV in
the ethernet frame. This operation will increase the frame size with up
to 32 bytes. If the frames are sent at line rate, the PHY will not have
enough room to insert the SecTAG and the ICV.

Some PHYs use a hardware buffer to store a number of ethernet frames and,
if it fills up, a pause frame is sent to the MAC to control the flow.
This HW implementation does not need any modification in the stack.

Other PHYs might offer to use a specific ethertype with some padding
bytes present in the ethernet frame. This ethertype and its associated
bytes will be replaced by the SecTAG and ICV.

mdo_insert_tx_tag allows the PHY drivers to add any specific tag in the
skb.

Signed-off-by: Radu Pirea (NXP OSS) <[email protected]>
---
Changes in v4:
- none

Changes in v3:
- improved insert_tx_tag flag description
- macsec_adjust_room uses the difference between MACsec room and
device room to adjust the macsec netdev room.
- macsec_update_offload return error instead of goto
- macsec_can_insert_tx_tag renamed to macsec_needs_tx_tag
- insert_tx_tag flag is checked in macsec_start_xmit
- "TX offload tag" replaced with "TX tag"

Changes in v2:
- added new fields documentation
- removed unnecesary checks in insert_tx_tag
- adjusted mdo_insert_tx_tag parameters. macsec_context replaced with
phy_device and sk_buff
- statistiscs incremented with DEV_STATS_INC
- improved patch description

drivers/net/macsec.c | 92 +++++++++++++++++++++++++++++++++++++++++++-
include/net/macsec.h | 10 +++++
2 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 2dde22e01fc1..eb26c1aa9b0f 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -93,6 +93,8 @@ struct pcpu_secy_stats {
* @secys: linked list of SecY's on the underlying device
* @gro_cells: pointer to the Generic Receive Offload cell
* @offload: status of offloading on the MACsec device
+ * @insert_tx_tag: when offloading, device requires to insert an
+ * additional tag
*/
struct macsec_dev {
struct macsec_secy secy;
@@ -102,6 +104,7 @@ struct macsec_dev {
struct list_head secys;
struct gro_cells gro_cells;
enum macsec_offload offload;
+ bool insert_tx_tag;
};

/**
@@ -2584,6 +2587,29 @@ static bool macsec_is_configured(struct macsec_dev *macsec)
return false;
}

+static bool macsec_needs_tx_tag(struct macsec_dev *macsec,
+ const struct macsec_ops *ops)
+{
+ return macsec->offload == MACSEC_OFFLOAD_PHY &&
+ ops->mdo_insert_tx_tag;
+}
+
+static void macsec_adjust_room(struct net_device *dev,
+ const struct macsec_ops *ops)
+{
+ int diff_headroom = MACSEC_NEEDED_HEADROOM - ops->needed_headroom;
+ int diff_tailroom = MACSEC_NEEDED_TAILROOM - ops->needed_tailroom;
+ struct macsec_dev *macsec = macsec_priv(dev);
+
+ if (macsec_is_offloaded(macsec)) {
+ dev->needed_headroom -= diff_headroom;
+ dev->needed_tailroom -= diff_tailroom;
+ } else {
+ dev->needed_headroom += diff_headroom;
+ dev->needed_tailroom += diff_tailroom;
+ }
+}
+
static int macsec_update_offload(struct net_device *dev, enum macsec_offload offload)
{
enum macsec_offload prev_offload;
@@ -2621,8 +2647,13 @@ static int macsec_update_offload(struct net_device *dev, enum macsec_offload off
ctx.secy = &macsec->secy;
ret = offload == MACSEC_OFFLOAD_OFF ? macsec_offload(ops->mdo_del_secy, &ctx)
: macsec_offload(ops->mdo_add_secy, &ctx);
- if (ret)
+ if (ret) {
macsec->offload = prev_offload;
+ return ret;
+ }
+
+ macsec_adjust_room(dev, ops);
+ macsec->insert_tx_tag = macsec_needs_tx_tag(macsec, ops);

return ret;
}
@@ -3380,6 +3411,52 @@ static struct genl_family macsec_fam __ro_after_init = {
.resv_start_op = MACSEC_CMD_UPD_OFFLOAD + 1,
};

+static struct sk_buff *macsec_insert_tx_tag(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct macsec_dev *macsec = macsec_priv(dev);
+ const struct macsec_ops *ops;
+ struct phy_device *phydev;
+ struct macsec_context ctx;
+ int err;
+
+ ops = macsec_get_ops(macsec, &ctx);
+ phydev = macsec->real_dev->phydev;
+
+ if (unlikely(skb_headroom(skb) < ops->needed_headroom ||
+ skb_tailroom(skb) < ops->needed_tailroom)) {
+ struct sk_buff *nskb = skb_copy_expand(skb,
+ ops->needed_headroom,
+ ops->needed_tailroom,
+ GFP_ATOMIC);
+ if (likely(nskb)) {
+ consume_skb(skb);
+ skb = nskb;
+ } else {
+ err = -ENOMEM;
+ goto cleanup;
+ }
+ } else {
+ skb = skb_unshare(skb, GFP_ATOMIC);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+ }
+
+ err = ops->mdo_insert_tx_tag(phydev, skb);
+ if (unlikely(err))
+ goto cleanup;
+
+ if (unlikely(skb->len - ETH_HLEN > macsec_priv(dev)->real_dev->mtu)) {
+ err = -EINVAL;
+ goto cleanup;
+ }
+
+ return skb;
+cleanup:
+ kfree_skb(skb);
+ return ERR_PTR(err);
+}
+
static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
@@ -3394,6 +3471,15 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
skb_dst_drop(skb);
dst_hold(&md_dst->dst);
skb_dst_set(skb, &md_dst->dst);
+
+ if (macsec->insert_tx_tag) {
+ skb = macsec_insert_tx_tag(skb, dev);
+ if (IS_ERR(skb)) {
+ DEV_STATS_INC(dev, tx_dropped);
+ return NETDEV_TX_OK;
+ }
+ }
+
skb->dev = macsec->real_dev;
return dev_queue_xmit(skb);
}
@@ -4127,6 +4213,10 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
err = macsec_offload(ops->mdo_add_secy, &ctx);
if (err)
goto del_dev;
+
+ macsec_adjust_room(dev, ops);
+ macsec->insert_tx_tag =
+ macsec_needs_tx_tag(macsec, ops);
}
}

diff --git a/include/net/macsec.h b/include/net/macsec.h
index 5e0b24a2f49c..9fd1103e1d36 100644
--- a/include/net/macsec.h
+++ b/include/net/macsec.h
@@ -316,6 +316,11 @@ struct macsec_context {
* @mdo_get_tx_sa_stats: called when TX SA stats are read
* @mdo_get_rx_sc_stats: called when RX SC stats are read
* @mdo_get_rx_sa_stats: called when RX SA stats are read
+ * @mdo_insert_tx_tag: called to insert the TX tag
+ * @needed_headroom: number of bytes reserved at the beginning of the sk_buff
+ * for the TX tag
+ * @needed_tailroom: number of bytes reserved at the end of the sk_buff for the
+ * TX tag
*/
struct macsec_ops {
/* Device wide */
@@ -342,6 +347,11 @@ struct macsec_ops {
int (*mdo_get_tx_sa_stats)(struct macsec_context *ctx);
int (*mdo_get_rx_sc_stats)(struct macsec_context *ctx);
int (*mdo_get_rx_sa_stats)(struct macsec_context *ctx);
+ /* Offload tag */
+ int (*mdo_insert_tx_tag)(struct phy_device *phydev,
+ struct sk_buff *skb);
+ unsigned int needed_headroom;
+ unsigned int needed_tailroom;
};

void macsec_pn_wrapped(struct macsec_secy *secy, struct macsec_tx_sa *tx_sa);
--
2.34.1