| From f428011b90ec0de7429886f753b7c3293392761c Mon Sep 17 00:00:00 2001 |
| From: Mark Starovoytov <mstarovoitov@marvell.com> |
| Date: Wed, 25 Mar 2020 15:52:36 +0300 |
| Subject: net: macsec: support multicast/broadcast when offloading |
| |
| The idea is simple. If the frame is an exact match for the controlled port |
| (based on DA comparison), then we simply divert this skb to matching port. |
| |
| Multicast/broadcast messages are delivered to all ports. |
| |
| Signed-off-by: Mark Starovoytov <mstarovoitov@marvell.com> |
| Signed-off-by: Igor Russkikh <irusskikh@marvell.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| --- |
| drivers/net/macsec.c | 51 ++++++++++++++++++++++++++++++++++++++------------- |
| 1 file changed, 38 insertions(+), 13 deletions(-) |
| |
| diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c |
| index 146a7881a20ac..c7ad7c6f1d1ec 100644 |
| --- a/drivers/net/macsec.c |
| +++ b/drivers/net/macsec.c |
| @@ -1006,22 +1006,53 @@ static enum rx_handler_result handle_not_macsec(struct sk_buff *skb) |
| { |
| /* Deliver to the uncontrolled port by default */ |
| enum rx_handler_result ret = RX_HANDLER_PASS; |
| + struct ethhdr *hdr = eth_hdr(skb); |
| struct macsec_rxh_data *rxd; |
| struct macsec_dev *macsec; |
| |
| rcu_read_lock(); |
| rxd = macsec_data_rcu(skb->dev); |
| |
| - /* 10.6 If the management control validateFrames is not |
| - * Strict, frames without a SecTAG are received, counted, and |
| - * delivered to the Controlled Port |
| - */ |
| list_for_each_entry_rcu(macsec, &rxd->secys, secys) { |
| struct sk_buff *nskb; |
| struct pcpu_secy_stats *secy_stats = this_cpu_ptr(macsec->stats); |
| + struct net_device *ndev = macsec->secy.netdev; |
| |
| - if (!macsec_is_offloaded(macsec) && |
| - macsec->secy.validate_frames == MACSEC_VALIDATE_STRICT) { |
| + /* If h/w offloading is enabled, HW decodes frames and strips |
| + * the SecTAG, so we have to deduce which port to deliver to. |
| + */ |
| + if (macsec_is_offloaded(macsec) && netif_running(ndev)) { |
| + if (ether_addr_equal_64bits(hdr->h_dest, |
| + ndev->dev_addr)) { |
| + /* exact match, divert skb to this port */ |
| + skb->dev = ndev; |
| + skb->pkt_type = PACKET_HOST; |
| + ret = RX_HANDLER_ANOTHER; |
| + goto out; |
| + } else if (is_multicast_ether_addr_64bits( |
| + hdr->h_dest)) { |
| + /* multicast frame, deliver on this port too */ |
| + nskb = skb_clone(skb, GFP_ATOMIC); |
| + if (!nskb) |
| + break; |
| + |
| + nskb->dev = ndev; |
| + if (ether_addr_equal_64bits(hdr->h_dest, |
| + ndev->broadcast)) |
| + nskb->pkt_type = PACKET_BROADCAST; |
| + else |
| + nskb->pkt_type = PACKET_MULTICAST; |
| + |
| + netif_rx(nskb); |
| + } |
| + continue; |
| + } |
| + |
| + /* 10.6 If the management control validateFrames is not |
| + * Strict, frames without a SecTAG are received, counted, and |
| + * delivered to the Controlled Port |
| + */ |
| + if (macsec->secy.validate_frames == MACSEC_VALIDATE_STRICT) { |
| u64_stats_update_begin(&secy_stats->syncp); |
| secy_stats->stats.InPktsNoTag++; |
| u64_stats_update_end(&secy_stats->syncp); |
| @@ -1033,19 +1064,13 @@ static enum rx_handler_result handle_not_macsec(struct sk_buff *skb) |
| if (!nskb) |
| break; |
| |
| - nskb->dev = macsec->secy.netdev; |
| + nskb->dev = ndev; |
| |
| if (netif_rx(nskb) == NET_RX_SUCCESS) { |
| u64_stats_update_begin(&secy_stats->syncp); |
| secy_stats->stats.InPktsUntagged++; |
| u64_stats_update_end(&secy_stats->syncp); |
| } |
| - |
| - if (netif_running(macsec->secy.netdev) && |
| - macsec_is_offloaded(macsec)) { |
| - ret = RX_HANDLER_EXACT; |
| - goto out; |
| - } |
| } |
| |
| out: |
| -- |
| cgit 1.2.3-1.el7 |
| |