Skip to content

Commit 9210319

Browse files
Shannon NelsonJeff Kirsher
authored andcommitted
ixgbe: process the Rx ipsec offload
If the chip sees and decrypts an ipsec offload, set up the skb sp pointer with the ralated SA info. Since the chip is rude enough to keep to itself the table index it used for the decryption, we have to do our own table lookup, using the hash for speed. Signed-off-by: Shannon Nelson <[email protected]> Tested-by: Andrew Bowers <[email protected]> Signed-off-by: Jeff Kirsher <[email protected]>
1 parent 6d73a15 commit 9210319

File tree

3 files changed

+115
-2
lines changed

3 files changed

+115
-2
lines changed

drivers/net/ethernet/intel/ixgbe/ixgbe.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,9 +1021,15 @@ s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg,
10211021
void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter);
10221022
void ixgbe_stop_ipsec_offload(struct ixgbe_adapter *adapter);
10231023
void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter);
1024+
void ixgbe_ipsec_rx(struct ixgbe_ring *rx_ring,
1025+
union ixgbe_adv_rx_desc *rx_desc,
1026+
struct sk_buff *skb);
10241027
#else
10251028
static inline void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter) { };
10261029
static inline void ixgbe_stop_ipsec_offload(struct ixgbe_adapter *adapter) { };
10271030
static inline void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter) { };
1031+
static inline void ixgbe_ipsec_rx(struct ixgbe_ring *rx_ring,
1032+
union ixgbe_adv_rx_desc *rx_desc,
1033+
struct sk_buff *skb) { };
10281034
#endif /* CONFIG_XFRM_OFFLOAD */
10291035
#endif /* _IXGBE_H_ */

drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,38 @@ static int ixgbe_ipsec_find_empty_idx(struct ixgbe_ipsec *ipsec, bool rxtable)
373373
return -ENOSPC;
374374
}
375375

376+
/**
377+
* ixgbe_ipsec_find_rx_state - find the state that matches
378+
* @ipsec: pointer to ipsec struct
379+
* @daddr: inbound address to match
380+
* @proto: protocol to match
381+
* @spi: SPI to match
382+
* @ip4: true if using an ipv4 address
383+
*
384+
* Returns a pointer to the matching SA state information
385+
**/
386+
static struct xfrm_state *ixgbe_ipsec_find_rx_state(struct ixgbe_ipsec *ipsec,
387+
__be32 *daddr, u8 proto,
388+
__be32 spi, bool ip4)
389+
{
390+
struct rx_sa *rsa;
391+
struct xfrm_state *ret = NULL;
392+
393+
rcu_read_lock();
394+
hash_for_each_possible_rcu(ipsec->rx_sa_list, rsa, hlist, spi)
395+
if (spi == rsa->xs->id.spi &&
396+
((ip4 && *daddr == rsa->xs->id.daddr.a4) ||
397+
(!ip4 && !memcmp(daddr, &rsa->xs->id.daddr.a6,
398+
sizeof(rsa->xs->id.daddr.a6)))) &&
399+
proto == rsa->xs->id.proto) {
400+
ret = rsa->xs;
401+
xfrm_state_hold(ret);
402+
break;
403+
}
404+
rcu_read_unlock();
405+
return ret;
406+
}
407+
376408
/**
377409
* ixgbe_ipsec_parse_proto_keys - find the key and salt based on the protocol
378410
* @xs: pointer to xfrm_state struct
@@ -476,7 +508,7 @@ static int ixgbe_ipsec_add_sa(struct xfrm_state *xs)
476508
}
477509

478510
/* get ip for rx sa table */
479-
if (xs->xso.flags & XFRM_OFFLOAD_IPV6)
511+
if (xs->props.family == AF_INET6)
480512
memcpy(rsa.ipaddr, &xs->id.daddr.a6, 16);
481513
else
482514
memcpy(&rsa.ipaddr[3], &xs->id.daddr.a4, 4);
@@ -541,7 +573,7 @@ static int ixgbe_ipsec_add_sa(struct xfrm_state *xs)
541573
rsa.mode |= IXGBE_RXMOD_PROTO_ESP;
542574
if (rsa.decrypt)
543575
rsa.mode |= IXGBE_RXMOD_DECRYPT;
544-
if (rsa.xs->xso.flags & XFRM_OFFLOAD_IPV6)
576+
if (rsa.xs->props.family == AF_INET6)
545577
rsa.mode |= IXGBE_RXMOD_IPV6;
546578

547579
/* the preparations worked, so save the info */
@@ -671,6 +703,78 @@ static const struct xfrmdev_ops ixgbe_xfrmdev_ops = {
671703
.xdo_dev_state_delete = ixgbe_ipsec_del_sa,
672704
};
673705

706+
/**
707+
* ixgbe_ipsec_rx - decode ipsec bits from Rx descriptor
708+
* @rx_ring: receiving ring
709+
* @rx_desc: receive data descriptor
710+
* @skb: current data packet
711+
*
712+
* Determine if there was an ipsec encapsulation noticed, and if so set up
713+
* the resulting status for later in the receive stack.
714+
**/
715+
void ixgbe_ipsec_rx(struct ixgbe_ring *rx_ring,
716+
union ixgbe_adv_rx_desc *rx_desc,
717+
struct sk_buff *skb)
718+
{
719+
struct ixgbe_adapter *adapter = netdev_priv(rx_ring->netdev);
720+
__le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
721+
__le16 ipsec_pkt_types = cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPSEC_AH |
722+
IXGBE_RXDADV_PKTTYPE_IPSEC_ESP);
723+
struct ixgbe_ipsec *ipsec = adapter->ipsec;
724+
struct xfrm_offload *xo = NULL;
725+
struct xfrm_state *xs = NULL;
726+
struct ipv6hdr *ip6 = NULL;
727+
struct iphdr *ip4 = NULL;
728+
void *daddr;
729+
__be32 spi;
730+
u8 *c_hdr;
731+
u8 proto;
732+
733+
/* Find the ip and crypto headers in the data.
734+
* We can assume no vlan header in the way, b/c the
735+
* hw won't recognize the IPsec packet and anyway the
736+
* currently vlan device doesn't support xfrm offload.
737+
*/
738+
if (pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPV4)) {
739+
ip4 = (struct iphdr *)(skb->data + ETH_HLEN);
740+
daddr = &ip4->daddr;
741+
c_hdr = (u8 *)ip4 + ip4->ihl * 4;
742+
} else if (pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPV6)) {
743+
ip6 = (struct ipv6hdr *)(skb->data + ETH_HLEN);
744+
daddr = &ip6->daddr;
745+
c_hdr = (u8 *)ip6 + sizeof(struct ipv6hdr);
746+
} else {
747+
return;
748+
}
749+
750+
switch (pkt_info & ipsec_pkt_types) {
751+
case cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPSEC_AH):
752+
spi = ((struct ip_auth_hdr *)c_hdr)->spi;
753+
proto = IPPROTO_AH;
754+
break;
755+
case cpu_to_le16(IXGBE_RXDADV_PKTTYPE_IPSEC_ESP):
756+
spi = ((struct ip_esp_hdr *)c_hdr)->spi;
757+
proto = IPPROTO_ESP;
758+
break;
759+
default:
760+
return;
761+
}
762+
763+
xs = ixgbe_ipsec_find_rx_state(ipsec, daddr, proto, spi, !!ip4);
764+
if (unlikely(!xs))
765+
return;
766+
767+
skb->sp = secpath_dup(skb->sp);
768+
if (unlikely(!skb->sp))
769+
return;
770+
771+
skb->sp->xvec[skb->sp->len++] = xs;
772+
skb->sp->olen++;
773+
xo = xfrm_offload(skb);
774+
xo->flags = CRYPTO_DONE;
775+
xo->status = CRYPTO_SUCCESS;
776+
}
777+
674778
/**
675779
* ixgbe_init_ipsec_offload - initialize security registers for IPSec operation
676780
* @adapter: board private structure

drivers/net/ethernet/intel/ixgbe/ixgbe_main.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1752,6 +1752,9 @@ static void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring,
17521752
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
17531753
}
17541754

1755+
if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_SECP))
1756+
ixgbe_ipsec_rx(rx_ring, rx_desc, skb);
1757+
17551758
skb->protocol = eth_type_trans(skb, dev);
17561759

17571760
/* record Rx queue, or update MACVLAN statistics */

0 commit comments

Comments
 (0)