On Mon, Dec 4, 2017 at 9:35 PM, Shannon Nelson <shannon.nel...@oracle.com> wrote: > 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 <shannon.nel...@oracle.com> > --- > drivers/net/ethernet/intel/ixgbe/ixgbe.h | 6 ++ > drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c | 89 > ++++++++++++++++++++++++++ > drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 3 + > 3 files changed, 98 insertions(+) > > diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h > b/drivers/net/ethernet/intel/ixgbe/ixgbe.h > index 7e8bca7..77f07dc 100644 > --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h > +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h > @@ -1009,9 +1009,15 @@ s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 > adv_reg, u32 lp_reg, > u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm); > #ifdef CONFIG_XFRM_OFFLOAD > void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter); > +void ixgbe_ipsec_rx(struct ixgbe_ring *rx_ring, > + union ixgbe_adv_rx_desc *rx_desc, > + struct sk_buff *skb); > void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter); > #else > static inline void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter) { > }; > +static inline void ixgbe_ipsec_rx(struct ixgbe_ring *rx_ring, > + union ixgbe_adv_rx_desc *rx_desc, > + struct sk_buff *skb) { }; > static inline void ixgbe_ipsec_restore(struct ixgbe_adapter *adapter) { }; > #endif /* CONFIG_XFRM_OFFLOAD */ > #endif /* _IXGBE_H_ */ > diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c > b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c > index b93ee7f..fd06d9b 100644 > --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c > +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c > @@ -379,6 +379,35 @@ static int ixgbe_ipsec_find_empty_idx(struct ixgbe_ipsec > *ipsec, bool rxtable) > } > > /** > + * ixgbe_ipsec_find_rx_state - find the state that matches > + * @ipsec: pointer to ipsec struct > + * @daddr: inbound address to match > + * @proto: protocol to match > + * @spi: SPI to match > + * > + * Returns a pointer to the matching SA state information > + **/ > +static struct xfrm_state *ixgbe_ipsec_find_rx_state(struct ixgbe_ipsec > *ipsec, > + __be32 daddr, u8 proto, > + __be32 spi) > +{ > + struct rx_sa *rsa; > + struct xfrm_state *ret = NULL; > + > + rcu_read_lock(); > + hash_for_each_possible_rcu(ipsec->rx_sa_list, rsa, hlist, spi) > + if (spi == rsa->xs->id.spi && > + daddr == rsa->xs->id.daddr.a4 && > + proto == rsa->xs->id.proto) { > + ret = rsa->xs; > + xfrm_state_hold(ret); > + break; > + } > + rcu_read_unlock(); > + return ret; > +} > +
You need to choose a bucket, not just walk through all buckets. Otherwise you might as well have just used a linked list. You might look at using something like jhash_3words to generate a hash which you then use to choose the bucket. > +/** > * ixgbe_ipsec_parse_proto_keys - find the key and salt based on the protocol > * @xs: pointer to xfrm_state struct > * @mykey: pointer to key array to populate > @@ -680,6 +709,66 @@ static const struct xfrmdev_ops ixgbe_xfrmdev_ops = { > }; > > /** > + * ixgbe_ipsec_rx - decode ipsec bits from Rx descriptor > + * @rx_ring: receiving ring > + * @rx_desc: receive data descriptor > + * @skb: current data packet > + * > + * Determine if there was an ipsec encapsulation noticed, and if so set up > + * the resulting status for later in the receive stack. > + **/ > +void ixgbe_ipsec_rx(struct ixgbe_ring *rx_ring, > + union ixgbe_adv_rx_desc *rx_desc, > + struct sk_buff *skb) > +{ > + struct ixgbe_adapter *adapter = netdev_priv(rx_ring->netdev); > + u16 pkt_info = > le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.pkt_info); > + u16 ipsec_pkt_types = IXGBE_RXDADV_PKTTYPE_IPSEC_AH | > + IXGBE_RXDADV_PKTTYPE_IPSEC_ESP; > + struct ixgbe_ipsec *ipsec = adapter->ipsec; > + struct xfrm_offload *xo = NULL; > + struct xfrm_state *xs = NULL; > + struct iphdr *iph; > + u8 *c_hdr; > + __be32 spi; > + u8 proto; > + > + /* we can assume no vlan header in the way, b/c the > + * hw won't recognize the IPsec packet and anyway the > + * currently vlan device doesn't support xfrm offload. > + */ > + /* TODO: not supporting IPv6 yet */ > + iph = (struct iphdr *)(skb->data + ETH_HLEN); > + c_hdr = (u8 *)iph + iph->ihl * 4; > + switch (pkt_info & ipsec_pkt_types) { > + case IXGBE_RXDADV_PKTTYPE_IPSEC_AH: > + spi = ((struct ip_auth_hdr *)c_hdr)->spi; > + proto = IPPROTO_AH; > + break; > + case IXGBE_RXDADV_PKTTYPE_IPSEC_ESP: > + spi = ((struct ip_esp_hdr *)c_hdr)->spi; > + proto = IPPROTO_ESP; > + break; > + default: > + return; > + } > + > + xs = ixgbe_ipsec_find_rx_state(ipsec, iph->daddr, proto, spi); > + if (unlikely(!xs)) > + return; > + > + skb->sp = secpath_dup(skb->sp); > + if (unlikely(!skb->sp)) > + return; > + > + skb->sp->xvec[skb->sp->len++] = xs; > + skb->sp->olen++; > + xo = xfrm_offload(skb); > + xo->flags = CRYPTO_DONE; > + xo->status = CRYPTO_SUCCESS; > +} > + > +/** > * ixgbe_init_ipsec_offload - initialize security registers for IPSec > operation > * @adapter: board private structure > **/ > diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c > b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c > index 6eabf92..60f9f2d 100644 > --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c > +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c > @@ -1755,6 +1755,9 @@ static void ixgbe_process_skb_fields(struct ixgbe_ring > *rx_ring, > > skb_record_rx_queue(skb, rx_ring->queue_index); > > + if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_SECP)) > + ixgbe_ipsec_rx(rx_ring, rx_desc, skb); > + > skb->protocol = eth_type_trans(skb, dev); > } > > -- > 2.7.4 > > _______________________________________________ > Intel-wired-lan mailing list > intel-wired-...@osuosl.org > https://lists.osuosl.org/mailman/listinfo/intel-wired-lan