Hi, I was on vacation and went through this mail thread just now. I wasn't sure where to inject my comments hence I am providing them at the top for clarity.
1). I am not a huge fan of the idea of starting a timer to perform the SA delete since calculating this timer's timeout will be an issue and will depend upon the network load at the specific time. 2). I get the feeling that this discussion is moving towards the earlier proposal from Dmitry to introduce a dummy packet to inform the application of the last packet which has been processed by this SA. correct me if I am wrong 3). I would really appreciate if you can summarize the discussion in form of a PR or RFC patch so we can debate on the exact changes for this proposal. Further comments inline... Regards, Bala On 18 October 2017 at 20:29, Bill Fischofer <bill.fischo...@linaro.org> wrote: > On Wed, Oct 18, 2017 at 7:38 AM, Pascal Van Leeuwen < > pvanleeu...@insidesecure.com> wrote: > >> Bill, >> >> >> >> I realize the complexity of coming with an abstraction that would suit all >> possible (existing) implementations. Therefore, I am completely open to >> making changes/improvements to our own implementation where this makes >> sense and can be done without completely reinventing the architecture >> (obviously). >> >> >> >> However, since I don’t have any knowledge regarding other implementations, >> I can only comment on what would work for ours, with some changes on our >> side. >> >> >> >> The problem with removing an SA from the lookup table immediately when >> odp_ipsec_disable() is called for our hardware would be that this lookup >> table is managed by software, completely asynchronously to our hardware. So >> you still have no way of knowing which packet that is already in the >> hardware (prior to the lookup stage) or already waiting to be fetched in an >> external ring buffer would be found and which packet would no longer be >> found. >> >> >> >> That's the reason why odp_ipsec_sa_disable() exists. It's assumed that >> there are some number of packets in flight that are in various stages of >> processing at the time of the call. From the application's perspective, the >> only packets that matter are those packets in the RX pipeline that the >> application has yet to see. Once a packet has been seen by the application >> it becomes the application's responsibility to track/account for it in >> deciding when it's safe to call odp_ipsec_sa_destroy(). >> >> >> >> The TX side is simple because the application initiates TX via the >> odp_ipsec_out_inline() API. So it's the application's responsibility to not >> make further calls to that API once it calls odp_ipsec_sa_disable(). So we >> only really need extra support from the ODP implementation on the RX side >> to account for packets that the application doesn't yet know about. >> >> >> >> Yes, I was talking about the RX side only because ODP does not actually >> support lookups by the IPsec HW for outbound (TX) operations (our HW does, >> by the way). >> > > That's good to know. I can see that capability being added to the API at > some point. You might want to make some suggestions for that. > > >> It makes sense that an application explicitly disabling a TX SA would not >> send anymore packets for that specific SA. I guess that’s the easy side >> then J >> >> >> >> I actually liked the idea of a **single** SA disable event being sent to >> the hardware, in our specific case by means of a dummy packet. This would >> allow us to mark the SA as being disabled and any packets behind it in the >> queue would see that and respond with some “SA already expired” error code. >> (actually, we could also automagically mark the SA disabled once we detect >> some preprogrammed packet count/octet count/timestamp threshold has been >> exceeded – or just provide some status code on the output for that) >> >> For our single pipe engines, that process everything strictly in-order, >> this would be fully deterministic. For our multi-pipe engines, there would >> still be some indeterminism due to packets being able to pass each other >> through different pipes, but at least it would be fairly limited. Either >> way, this indeterminism needs to be taken into account somehow. Since you mention about multi-pipe engines, the ODP API specifies that the packet received in the queue should maintain packet order per SA. Hence you should process packets belonging to a single SA in a single pipe else implement some mechanism in your implementation to make sure that packet belonging to a single SA maintain packet order. Do you have any issue in your HW to maintain packet order per SA? >> >> >> >> If I understand this approach, odp_ipsec_sa_disable() would operate by >> injecting a special "disable" packet via a loopback interface or similar >> into the RX packet stream. >> >> I don’t know enough about the ODP API (yet) to comment on ODP specifics. >> For our hardware, the packet would have to be injected into the input >> /packet/ ring buffer (the same one used for normal processing), basically >> at the exact point in time where you would want to stop allowing newly >> arriving packets from using the SA. >> > > That's one of the effects of odp_ipsec_sa_disable(), after that call no > further packets should be accepted for processing on this SA. They are > treated as an SA lookup failure. > > >> >> >> This would serve both to initiate the disable as well as to serve as the >> status event that indicates that the RX pipeline has been flushed. That >> would certainly be a valid implementation of the currently-defined disable >> semantics. >> >> >> >> When you refer to "multi-pipe engines" presumably that means you have two >> or more IPsec HW blocks operating in parallel that are fed by the RX queues. >> >> Actually it’s one IPsec hardware block scheduling packets from potentially >> a single input queue, using potentially a single shared SA, over multiple >> processing pipelines while maintaining proper sequence numbering/checking. >> >> >> >> Can operations from the same SA be in two different blocks at the same >> time? >> >> Yes! This is one of our major selling points: we can process a single SA >> over multiple processing pipes, allowing us to achieve very high single SA >> throughput. >> > > ODP uses ordered queues and locks to achieve the same by allowing multiple > cores to work on a single flow in parallel. It's a useful abstraction. > > >> >> >> Since IPsec operations assume sequentiality I'd assume either there would >> be some sort of interlock to prevent that or else there is inter-block >> coordination to assure that things like sequence numbers are handled >> properly. >> >> We are purposely not interlocking our pipes as that would kill performance >> when processing a mix of packets with a large delta in packet size (e.g. >> IMIX). >> So we indeed have some coordination hardware between the processing pipes >> to handle sequence numbers properly. >> >> >> >> Then, once the status result of the SA disable event has been seen at the >> output of our engine, the SA could finally be removed from the lookup >> table. And some time after that – I guess you would need some kind of >> time-out for that, as our hardware still needs it until all pending packets >> have passed the lookup stage – it could finally be destroyed and removed >> from memory. >> >> >> >> The question of lookup table vs. back-end processing and result queueing >> is an interesting one. Can an SA be removed/deactivated from lookup without >> also unhooking it from the rest of the IPsec processing machinery? >> >> I guess so. Removing the entry from the lookup table would just prevent it >> from being found. Any packets already past the lookup stage would still be >> able to use it as long as the SA data still exists in external memory. The >> problem is that you don’t really know which packets live where in the pipe >> at the time of removing the entry from the table. >> > > That's OK, as long as lookup is done once and the results of that lookup > are carried with the packet as it works its way through the pipeline. Any > packet that makes it past lookup before the disable call removes the SA > from lookup processing should be handled normally. > > >> So you don’t really know which packets that have already been enqueued >> would end up not finding the SA because it was removed from the table while >> they were waiting to be processed. >> > > If the lookup is done multiple times during the course of packet processing > that would be a problem. In that case your special "disable packet" marker > would serve the same purpose as any packets seen after it would be > discarded. > > >> Having an explicit SA disable event travelling /together/ with the packet >> stream would give you better control over that. If you need that at all, >> that is. >> >> >> >> Our current disable semantics assume that it can. If that's not possible >> then I can see where that would cause issues in trying to map these >> semantics to HW. >> >> >> >> Another approach would be to handle this as the SA queue level rather than >> the SA itself. The SA completion queue contains packets that have completed >> RX input processing and are ready for the application to see. However, >> until the application sees them it's indistinguishable where the packets >> are between the wire and this queue, so simply flushing the queue and >> pretending that all of these unseen packets were still on the wire and had >> not yet arrived at the time odp_ipsec_sa_disable(0 was called is also >> legitimate. >> >> Hmm … but if you flush that queue you would lose the packets? I guess with >> ethernet & IP not supposed to be reliable protocols that is sort of legal, >> and I suppose SA disables should not happen all too frequently, but it >> still seems to be a bit ugly to me. >> > > It's perfectly fine to drop packets for good reason. Since SA disables (for > tunnels, at least) are relatively rare events this should have no > meaningful impact on overall operation or performance. For "short session" > SAs, where an SA exists to handle only a single burst of packets, chances > are the higher-level protocol will signal completion and the > disable/destroy will be happening on an empty pipeline anyway, so there > will be nothing to discard. > > >> >> >> Regards, >> >> Pascal >> >> >> >> [image: >> http://medias.infostrates.fr/b2c/insidesecure/signatureMail/inside-logo-signature.jpg] >> >> *Pascal van Leeuwen* >> Senior IC Design Engineer >> >> Tel. : +31 (0)73 65 81 900 >> >> >> www.insidesecure.com >> >> >> >> >> >> CONFIDENTIALITY - This e-mail and any attachments hereto are intended only >> for use by the addressee(s) named herein and may contain confidential >> information. If you are not the named recipient, please notify the sender >> immediately and do not disclose the contents to any person, use it for any >> purpose, or store or copy the information on any medium. Please permanently >> delete the original copy of this e-mail and/or any attachments thereto and >> any printout thereof. Thank you. >> >> >> >> *From:* Bill Fischofer [mailto:bill.fischo...@linaro.org] >> *Sent:* Wednesday, October 18, 2017 3:36 AM >> *To:* lng-odp-forward <lng-odp@lists.linaro.org>; Pascal Van Leeuwen < >> pvanleeu...@insidesecure.com> >> *Subject:* Latest odp_ipsec_sa_disable() discussion and proposed >> resolution >> >> >> >> We discussed this during the ODP public call today and had the benefit of >> Pascal Van Leeuwen's participation. Pascal is a HW guy and explained some >> of the issues that HW IPsec support faces. >> >> >> >> HW recognizes an active SA by it being in a HW lookup table. From an ODP >> implementation perspective, odp_ipsec_sa_create() allocates an SA, >> initializes it, and inserts it into the lookup table to activate it. The >> question is how is the SA removed from the lookup table. There are two >> possible approaches. >> >> >> >> 1. It can be removed by odp_ipsec_sa_disable() >> >> 2. It can be removed by odp_ipsec_sa_destroy() >> >> >> >> The suggestion is that it be removed by odp_ipsec_sa_disable(). This >> accomplishes the goal of ensuring that no further inbound IPsec packets are >> recognized as belonging to this SA (they will appear on the pktio default >> queue and/or passed to the classifier for processing as-is). >> >> >> >> However, at the time odp_ipsec_sa_disable() is called, there may be one or >> more IPsec packets from that SA in process. In general, this processing may >> be carried out in parallel and the order in which packets exit the IPsec HW >> may not be determinate. Some implementations may be able to determine >> directly when these packets belonging to this SA have cleared the various >> IPsec HW blocks and have reached the SA queue. However absent such ability >> each implementation should be able to determine a maximum wait time after >> which it can be assured that any in-progress IPsec packet has completed >> whatever HW processing might have been in progress at the time >> odp_ipsec_sa_disable() was called. >> >> >> >> This leads to the following suggested implementation logic, which adheres >> to the original odp_ipsec_sa_disable() semantics: >> >> >> >> - Upon receiving the odp_ipsec_sa_disable() call, remove the SA from any >> HW lookup table(s) >> >> >> >> - Set an internal timer (implementation dependent) sufficient to allow all >> in-flight IPsec HW operations to complete. >> >> >> >> - Return 0 to indicate disable is in progress >> >> >> >> At this point no further inbound IPsec packets for this SA will be >> recognized and any that are on the queue associated with the SA will be >> processed by the application. This queue may or may not drain completely by >> the time the implementation-internal disable timer expires, but we can be >> sure that any in-flight IPsec packets are at least on this queue. >> >> >> >> When the internal timer expires, the implementation has two choices. >> >> >> >> - If it is able to add elements to the SA queue, it can add an >> ODP_EVENT_IPSEC_STATUS event to signal disable completion. >> >> >> >> - If it is unable to add elements to the SA queue, it can set internal >> metadata associated with the SA queue such that odp_queue_deq() or the >> scheduler will recognize that this "empty" queue needs to report a >> pseudo-status event. This can then be created and returned in response to >> this call and the associated internal queue metadata cleared. >> >> >> >> This combination of actions should result in the current >> odp_ipsec_sa_disable() semantics being realized. >> >> >> >> The implementation has broad flexibility in how this may be done. For >> example, a software "shadow queue" could be created that has priority >> strictly lower than the main SA queue such that it will never be examined >> if the SA queue contains any elements. Upon timer expiration the required >> status event could be added to this shadow queue such that it will only be >> dequeued after the SA queue is empty. The shadow queue would also have the >> property that it would report the same queue identity as its SA "parent" >> (the shadow being invisible to application SW) and thus serves only to work >> around cases where SW cannot add elements directly to the HW SA queue. >> >> >> >> I'd appreciate if those with direct knowledge of HW IPsec implementations >> could comment on whether this sort of approach is feasible on their >> platforms. >> >> >> >> >>