<div><span style="color: rgb(160, 160, 168); ">On Friday, February 15, 2013 at 3:40 PM, Navarro, Galo wrote:</span></div>
                <blockquote type="cite" style="border-left-style:solid;border-width:1px;margin-left:0px;padding-left:10px;">
                    <span><div><div><div>Hello dev force!</div></div></div></span></blockquote><div>Galo, thanks for the write-up! </div><blockquote type="cite" style="border-left-style:solid;border-width:1px;margin-left:0px;padding-left:10px;"><span><div><div><div><br></div><div>I'm sending below a draft proposal for issue #435. Thanks in advance</div><div>for any comments / doubts / corrections / suggestions / improvements.</div><div><br></div><div># Use case</div><div><br></div><div>Currently it's impossible to ping from a private network behind NAT to</div><div>an external address. Translation is not applied for ICMP because</div><div>lacking ports, we'd need to match on additional ICMP-specific fields</div><div>that are not supported by OpenFlow nor OVS, so it in practise we can't</div><div>route ICMP replies back to the correct sender.</div><div><br></div><div>This feature is typically supported by iptables and commodity routers,</div><div>so we'd like to make Midonet able to circumvent OVS/OpenFlow's</div><div>limitations. This will involve:</div><div><br></div><div>1. Implementing ICMP packets in NAT rules</div><div>2. Forcing user-space processing for ICMP req/repl</div><div><br></div><div>## Support ICMP messages in NAT rules</div><div><br></div><div>For ICMP messages, the identifier would act as transport source /</div><div>destination (see [RFC3022][1], esp. sections 2.2 and 4.1, as well as</div><div>[RFC5508][2]). The NatLeaseManager would treat these as ports, thus</div><div>being able to discriminate origins of ICMP echo requests sent to the</div><div>same destination:</div><div><br></div><div>If both A and B send an ICMP(src,dst,type,id) to Z accross a router R.</div><div><br></div><div>- A sends ICMP(A,Z,req,x), R translates to ICMP(R,Z,req,x')</div><div>- B sends ICMP(B,Z,req,y), R translates to ICMP(R,Z,req,y')</div><div><br></div><div>Nat mappings are: (A,x,Z,x') and (B,y,Z,x'). Thus:</div></div></div></span></blockquote><div>I asked Galo about the exact key-value pairs we would write to Cassandra and he explained (for the ICMP from A):</div><div>forward-key: (A, id, Z, id) --- ip_src, tp_src, ip_dst, tp_dst  - I think that's the order in the code.</div><div>forward-value (R, id)......       or (R, id') if we're translating the identifier</div><div>return-key: (R, id, Z, id)......      or (R, id', Z, id') if we're translating the identifier</div><div>return-value: (A, id)</div><div><br></div><div>But we probably will NOT translate the identifier - and just rely on ICMP's random choice of identifier to avoid conflicts/collisions.</div><blockquote type="cite" style="border-left-style:solid;border-width:1px;margin-left:0px;padding-left:10px;"><span><div><div><div><br></div><div>- Z sends ICMP(Z,R,rep,x'), R translates to ICMP(Z,A,rep,x)</div><div>- Z sends ICMP(Z,R,rep,y'), R translates to ICMP(Z,B,rep,y)</div><div><br></div><div>One benefit of this approach is that we'd be able to reuse most of the</div><div>NatMapping code, rather than writing separate mapping for ICMP messages</div><div>alone. The main insufficiency of the current implementation comes from</div><div>the possibility of clashes between ICMP identifiers and port numbers</div><div>used by other applications This is solved in practise by including the</div><div>protocol in the mapping criteria (found references to this in [3] and</div><div>[4]).</div><div><br></div><div>This solution would require adding the protocol to the current</div><div>NatLeaseManager + NatMapping. The logic to allocate a NAT lease would</div><div>work like this:</div><div><br></div><div>- TCP/UDP: identical to current implementation</div><div>- ICMP: lease the ICMP identifier as both source and destination "port"</div></div></div></span></blockquote><div>lease->use?</div><blockquote type="cite" style="border-left-style:solid;border-width:1px;margin-left:0px;padding-left:10px;"><span><div><div><div><br></div><div>This leaves one chance of collision (both A and B may send an ICMP req</div><div>with the same identifier, R won't be able to reverse-translate). To get</div><div>around this we can:</div><div>1. Drop an ICMP echo request if the identifier is already leased. These</div><div>   leases should probably have a low TTL.</div><div>2. Make the NatLeaseManager hold a separate list of free identifiers and</div><div>   assign them similarly as is done for ports.</div><div><br></div><div>(1) provides less complexity at the cost of some dropped ICMP requests</div></div></div></span></blockquote><div>In our chat we agreed to avoid any 'reservation' of identifiers that looks like SNAT today.</div><div>(We're trying to deprecate the SNAT block leases in favor of randomly selecting the SNAT port)</div><blockquote type="cite" style="border-left-style:solid;border-width:1px;margin-left:0px;padding-left:10px;"><span><div><div><div><br></div><div>## Force userspace processing of ICMP messages</div><div><br></div><div>This is necessary because ODP does not parse the identifier fields of</div><div>the ICMP messages which is the only way to map src and dst accross a</div><div>NAT.</div><div><br></div><div>1. Simulate ICMP messages should be simulated normally, but never</div><div>   produce installed flows.</div><div>2. Make ForwardNatRule and ReverseNatRule deal with ICMP by themselves.</div><div><br></div><div>Rules are only provided with context that may be relevant for installed</div><div>flows, so the ICMP identifier is not there and NAT rules cannot perform</div><div>the translation. There are various options to solve this:</div><div><br></div><div>- Make the Router artificially set the WildcardMatch's transport dst and</div><div>  src to the ICMP identifier before they enter chain.apply. This</div><div>  approach is problmatic considering that non-NAT rules will suddenly</div><div>  need to deal with a NAT-specific hack. Also, this solution will simply</div><div>  not work to support ICMP errors since, as it will be explained further</div><div>  down, we'll need rules to examine the contents of the ICMP payload.</div><div>- Extend WildcardMatch to include either the original packet so</div><div>  that each rule can simply examine the contents freely.</div><div>- Extend WildcardMatch adding the ICMP source/dst identifier.</div></div></div></span></blockquote><div>Here's an idea that came up while we were chatting:</div><div><br></div><div>Extend WildcardMatch like this:</div><div>- it has a new field 'icmp_echo_identifier'</div><div>- when parsing a packet to make a WMatch, if it's an ICMP echo request or reply,</div><div>fill the icmp_echo_identifier field</div><div><br></div><div>Now, when we simulate an ICMP traversing a NAT, after we decide the mapping,</div><div>we have enough expressive power in the WMatch that we can make wildcarded</div><div>flows that deal with ICMP of a specific identifier.</div><div><br></div><div>So, all ICMPs will come up to Midolman, but only the first one in the flow will</div><div>need to be simulated. Subsequent ones will be matched in the Wildcard Flow</div><div>Table and immediately result in an 'emit' command to the datapath (because as</div><div>you said we shouldn't install kernel flows or we'll get incorrect behavior - won't be</div><div>identifier specific).</div><div><br></div><div>thanks!</div><div>Pino</div><blockquote type="cite" style="border-left-style:solid;border-width:1px;margin-left:0px;padding-left:10px;"><span><div><div><div><br></div><div>The last option seems better because it makes it easy to reflect that,</div><div>in fact, we're extending the packet parsing capabilities of ODP.</div><div><br></div><div>WildcardMatch would start including "ODP-supported" fields, and</div><div>"ODP-unsupported" fields (ICMP id and payload would be part of these).</div><div>MM will emit the modified packet, but when it comes to installing new</div><div>flows the FlowController will simply ignore those that involve</div><div>unsupported matching fields. If further versions of ODP start parsing</div><div>unsupported fields, the corresponding flows can start being installed.</div><div><br></div><div>## Further support for ICMP error messages (#513)</div><div><br></div><div>As Jacob mentions one of the most important ICMP error messages to</div><div>support accross NAT would be ICMP Destination Unreachable, esp.</div><div>fragmentation required, etc. An ICMP error from Z to A triggered in</div><div>response to a TCP packet NAT'ed by R would look like this:</div><div><br></div><div>    ICMP(Z,R,dest-unreachable,frag-reqd, (A,x',Z,y'))</div><div><br></div><div>By examining the payload R would be able to use the payload for the</div><div>reverse mapping and deliver the ICMP error to A:</div><div><br></div><div>    ICMP(Z,A,dest-unreachable,frag-reqd, (A,x,Z,y))</div><div><br></div><div>## API changes</div><div><br></div><div>Initially it should not necessarily involve any API changes since most</div><div>of the work is localized in core code, but since part of the proposal</div><div>involves adding the protocol to NAT rules it may be considered to</div><div>expose this field also in the API as part of this issue.</div><div><br></div><div>## References</div><div><br></div><div>[1]: <<a href="http://tools.ietf.org/html/rfc3022">http://tools.ietf.org/html/rfc3022</a>></div><div>[2]: <<a href="http://tools.ietf.org/html/rfc5508#page-6">http://tools.ietf.org/html/rfc5508#page-6</a>></div><div>[3]: <<a href="http://hasenstein.com/linux-ip-nat/diplom/node6.html">http://hasenstein.com/linux-ip-nat/diplom/node6.html</a>></div><div>[4]: <<a href="http://superuser.com/questions/135094/how-does-a-nat-server-forward-ping-icmp-echo-reply-packets-to-users#135098">http://superuser.com/questions/135094/how-does-a-nat-server-forward-ping-icmp-echo-reply-packets-to-users#135098</a>></div><div><br></div><div>Cheers!</div><div>/g</div></div></div></span>
                 
                 
                 
                 
                </blockquote>
                 
                <div>
                    <br>
                </div>