<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>higebu.com</title><link>https://www.higebu.com/en/</link><description>北海道に住んでいるソフトウェアエンジニア。 ネットワークプロトコルやモバイルコアに興味があります。 4人の子供の父親。</description><language>en</language><managingEditor>yuya.kusakabe@gmail.com (Yuya Kusakabe)</managingEditor><lastBuildDate>Thu, 01 Oct 2026 00:00:00 +0900</lastBuildDate><atom:link href="https://www.higebu.com/en/index.xml" rel="self" type="application/rss+xml"/><item><title>Why was Linux SRv6 H.Encaps.L2 still slow with tunsrc set?</title><link>https://www.higebu.com/en/blog/2026/10/01/srv6-l2encap/</link><pubDate>Thu, 01 Oct 2026 00:00:00 +0900</pubDate><guid>https://www.higebu.com/en/blog/2026/10/01/srv6-l2encap/</guid><description>&lt;p&gt;In the &lt;a href="https://www.higebu.com/en/blog/2026/09/25/srv6-tunsrc/"&gt;previous post&lt;/a&gt;, setting tunsrc made both H.Encaps.V6 and H.Encaps.L2 faster. Even so, H.Encaps.L2 stayed at 660.7 kpps against 976.4 kpps for H.Encaps.V6 (both PDR, with tunsrc set). For the same input packets, H.Encaps.L2 additionally carries the 14-byte inner Ethernet header, which should not cost a third of the throughput. It turned out to be an unnecessary memory allocation on every packet, and the fix is now in net-next.&lt;/p&gt;
&lt;h2 id="test-setup"&gt;Test setup&lt;/h2&gt;
&lt;p&gt;Everything below was measured on net-next, just before and at the fix, built from the same configuration (based on Ubuntu&amp;rsquo;s, with &lt;code&gt;CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y&lt;/code&gt;). The SUT (the machine under test) has a Xeon E5-2650 v3 at 2.30 GHz and forwards 64-byte frames on a single core, connected back to back to a T-Rex tester with Intel 82599ES (ixgbe) NICs, with &lt;code&gt;iommu=pt&lt;/code&gt; and tunsrc set. Throughput is measured with &lt;a href="https://github.com/higebu/SRPerf/tree/f91e3cd0508e47905df7e2f04c83ae1085a50f12"&gt;my fork of SRPerf&lt;/a&gt; (updated to run on Ubuntu 24.04 and Python 3.12) as in the previous post: PDR (Partial Drop Rate, the highest offered rate with at most 0.5% packet loss) and MRR (Maximum Receive Rate, the receive rate when sending at line rate).&lt;/p&gt;
&lt;h2 id="what-the-flame-graph-showed"&gt;What the flame graph showed&lt;/h2&gt;
&lt;p&gt;I took a flame graph of the forwarding core while sending H.Encaps.L2 traffic at a fixed 500 kpps, which the kernel before the fix forwards without loss.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.higebu.com/images/20261001-srv6-l2encap-before.svg" alt="H.Encaps.L2 flame graph before the fix"&gt;&lt;/p&gt;
&lt;p&gt;Including their callees, &lt;code&gt;pskb_expand_head()&lt;/code&gt; takes 21.1% of the sampled cycles, &lt;code&gt;kmalloc_reserve()&lt;/code&gt; 18.7% and &lt;code&gt;memset_orig()&lt;/code&gt; 14.1%. Every &lt;code&gt;memset_orig()&lt;/code&gt; sample is on the path &lt;code&gt;seg6_do_srh()&lt;/code&gt; → &lt;code&gt;pskb_expand_head()&lt;/code&gt; → &lt;code&gt;kmalloc_reserve()&lt;/code&gt;, so the zeroing comes from reallocating the skb head. The code shows that this happens on every packet.&lt;/p&gt;
&lt;h2 id="why-the-skb-head-was-reallocated-on-every-packet"&gt;Why the skb head was reallocated on every packet&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;seg6_do_srh()&lt;/code&gt; in &lt;code&gt;net/ipv6/seg6_iptunnel.c&lt;/code&gt; pushes the Ethernet header back in front of the packet before building the outer IPv6 header, and in the L2 encapsulation modes it called &lt;code&gt;pskb_expand_head()&lt;/code&gt; unconditionally to make room for it. &lt;code&gt;pskb_expand_head()&lt;/code&gt; always allocates a new head and copies the headroom and the linear data into it, even when the existing headroom is already large enough. The IPv6 encapsulation modes use &lt;code&gt;skb_cow_head()&lt;/code&gt; instead, which reallocates only when the headroom is too small or the head is shared with a clone.&lt;/p&gt;
&lt;p&gt;In this setup, the skb reaches &lt;code&gt;seg6_do_srh()&lt;/code&gt; with 206 bytes of headroom, while a single-segment L2 encapsulation needs 94 bytes (14 for the Ethernet header, 40 for the IPv6 header, 24 for the SRH and 16 reserved for the outgoing link layer). The skbs were not cloned either, so the reallocation was not needed.&lt;/p&gt;
&lt;p&gt;The cost is made larger by &lt;code&gt;CONFIG_INIT_ON_ALLOC_DEFAULT_ON&lt;/code&gt;. This is a hardening option, added in Linux 5.3, that zero-fills page and slab allocations to reduce the risk of exposing stale data. Ubuntu and Debian enable it by default, and it was enabled in the kernels here, so every reallocated head was also cleared with &lt;code&gt;memset()&lt;/code&gt;. It can be turned off with &lt;code&gt;init_on_alloc=0&lt;/code&gt;, but turning off a security feature to win back performance is the wrong way around; not reallocating is the better fix.&lt;/p&gt;
&lt;p&gt;The unconditional reallocation itself dates back to when H.Encaps.L2 was added in 2017, so the kernel used in the &lt;a href="https://doi.org/10.1109/TNSM.2020.3048328"&gt;SRPerf paper&lt;/a&gt; (net-next during the 5.2 cycle) had it as well. That kernel predates &lt;code&gt;init_on_alloc&lt;/code&gt;, which was merged in 5.3, though, and in the paper H.Encaps.L2 was much closer to H.Encaps.V6 (about 828 against 978 kpps, 0.85). To see how much of the gap came from the zeroing, I booted the kernel before the fix with &lt;code&gt;init_on_alloc=0&lt;/code&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;init_on_alloc&lt;/th&gt;
&lt;th&gt;H.Encaps.V6&lt;/th&gt;
&lt;th&gt;H.Encaps.L2&lt;/th&gt;
&lt;th&gt;L2/V6&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1 (default)&lt;/td&gt;
&lt;td&gt;937.7&lt;/td&gt;
&lt;td&gt;644.0&lt;/td&gt;
&lt;td&gt;0.69&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;938.0&lt;/td&gt;
&lt;td&gt;773.9&lt;/td&gt;
&lt;td&gt;0.83&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;(MRR in kpps, mean of 10 runs, before the fix)&lt;/p&gt;
&lt;p&gt;Without the zeroing, L2/V6 goes from 0.69 to 0.83, close to the paper.&lt;/p&gt;
&lt;h2 id="the-fix"&gt;The fix&lt;/h2&gt;
&lt;p&gt;The fix asks &lt;code&gt;skb_cow_head()&lt;/code&gt; for the whole encapsulation up front:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-diff" data-lang="diff"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gd"&gt;- if (pskb_expand_head(skb, skb-&amp;gt;mac_len, 0, GFP_ATOMIC) &amp;lt; 0)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gd"&gt;- return -ENOMEM;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gi"&gt;+ headroom = skb-&amp;gt;mac_len + sizeof(struct ipv6hdr) +
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gi"&gt;+ ipv6_optlen(tinfo-&amp;gt;srh) +
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gi"&gt;+ dst_dev_overhead(cache_dst, skb);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gi"&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gi"&gt;+ err = skb_cow_head(skb, headroom);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gi"&gt;+ if (unlikely(err))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gi"&gt;+ return err;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When the headroom is large enough and the skb is not cloned, nothing is reallocated. When the headroom really is too small, the head is reallocated once, and the later &lt;code&gt;skb_cow_head()&lt;/code&gt; in the IPv6 encapsulation code then finds the room it needs instead of reallocating a second time.&lt;/p&gt;
&lt;p&gt;After the fix, the allocation no longer appears in the flame graph under the same load:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.higebu.com/images/20261001-srv6-l2encap-after.svg" alt="H.Encaps.L2 flame graph after the fix"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pskb_expand_head()&lt;/code&gt;, &lt;code&gt;kmalloc_reserve()&lt;/code&gt; and &lt;code&gt;memset_orig()&lt;/code&gt; have no samples left, and &lt;code&gt;seg6_do_srh()&lt;/code&gt; falls from 28.2% to 5.6% of the cycles. Dividing the cycles of each 30-second capture by the 15 million packets forwarded in it, the core spends 2602 cycles per packet instead of 3862.&lt;/p&gt;
&lt;h2 id="measurement"&gt;Measurement&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;H.Encaps.L2 PDR&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;before the fix&lt;/td&gt;
&lt;td&gt;654.6 kpps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;after the fix&lt;/td&gt;
&lt;td&gt;965.7 kpps (+47.5%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;(mean of 10 PDR searches, each using 10-second trials)&lt;/p&gt;
&lt;p&gt;H.Encaps.V6 does not take this code path, and its MRR stays at about 938 kpps on both kernels. With &lt;code&gt;init_on_alloc=0&lt;/code&gt;, the kernel with the fix gives an L2/V6 ratio of 1.02 (956.8 against 939.1 kpps MRR): H.Encaps.L2 is as fast as H.Encaps.V6, so the gap that was left after removing the zeroing was the reallocation.&lt;/p&gt;
&lt;h2 id="getting-it-upstream"&gt;Getting it upstream&lt;/h2&gt;
&lt;p&gt;The first version only asked &lt;code&gt;skb_cow_head()&lt;/code&gt; for &lt;code&gt;skb-&amp;gt;mac_len&lt;/code&gt;. &lt;a href="https://lore.kernel.org/r/CANn89iKUqjbrRkr68&amp;#43;S9nKAu49C3K01e3XSNwkY1NCgmuPMPag@mail.gmail.com"&gt;Eric Dumazet pointed out&lt;/a&gt; that a header-cloned skb could then still be reallocated twice, once to unclone it and again for the outer header, so the second version asked for the whole encapsulation as above.&lt;/p&gt;
&lt;p&gt;While reviewing the second version, &lt;a href="https://lore.kernel.org/r/178885587111.219967.14896644410984520593@kernel.org"&gt;Sashiko, the AI review bot on netdev, found a different bug&lt;/a&gt;. &lt;code&gt;dst_dev_overhead()&lt;/code&gt; reserves room for the egress device&amp;rsquo;s link-layer header, but the code rebuilds the ingress MAC header in front of the packet. When the ingress MAC header is longer, for example a VLAN-tagged frame received with &lt;code&gt;reorder_hdr off&lt;/code&gt;, the offset of the rebuilt header wraps around and the copy lands about 64 KB past the buffer. This was not specific to the L2 modes, so I fixed it separately in &lt;code&gt;dst_dev_overhead()&lt;/code&gt; and sent it to the net tree. That fix was merged first, and the third version of this patch went into net-next, which currently tracks 7.3-rc, so it should be in Linux 7.4.&lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://git.kernel.org/netdev/net-next/c/bf515c9fae87"&gt;seg6: reallocate the skb head on L2 encapsulation only when needed&lt;/a&gt; (net-next, bf515c9fae87)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.kernel.org/netdev/net/c/87cd6b717e40"&gt;net: ipv6: keep room for the mac header in dst_dev_overhead()&lt;/a&gt; (net, 87cd6b717e40)&lt;/li&gt;
&lt;li&gt;Patch threads: &lt;a href="https://lore.kernel.org/r/20260902-seg6-l2cow-v1-1-e823ce216454@gmail.com"&gt;v1&lt;/a&gt;, &lt;a href="https://lore.kernel.org/r/20260925-seg6-l2cow-v3-1-fc83821542a7@gmail.com"&gt;v3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A. Abdelsalam, P. L. Ventre, C. Scarpitta, A. Mayer, S. Salsano, P. Camarillo, F. Clad, C. Filsfils, &amp;ldquo;&lt;a href="https://doi.org/10.1109/TNSM.2020.3048328"&gt;SRPerf: A Performance Evaluation Framework for IPv6 Segment Routing&lt;/a&gt;&amp;rdquo;, IEEE Transactions on Network and Service Management, vol. 18, no. 2, pp. 2320-2333, 2021&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.kernel.org/admin-guide/kernel-parameters.html"&gt;The kernel&amp;rsquo;s command-line parameters: init_on_alloc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/SRouting/SRPerf"&gt;SRPerf&lt;/a&gt; (GitHub) and &lt;a href="https://github.com/higebu/SRPerf/tree/f91e3cd0508e47905df7e2f04c83ae1085a50f12"&gt;my fork&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.higebu.com/en/blog/2026/09/25/srv6-tunsrc/"&gt;How much slower is Linux SRv6 H.Encaps without tunsrc?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/brendangregg/FlameGraph"&gt;Brendan Gregg&amp;rsquo;s FlameGraph&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>How much slower is Linux SRv6 H.Encaps without tunsrc?</title><link>https://www.higebu.com/en/blog/2026/09/25/srv6-tunsrc/</link><pubDate>Fri, 25 Sep 2026 00:00:00 +0900</pubDate><guid>https://www.higebu.com/en/blog/2026/09/25/srv6-tunsrc/</guid><description>&lt;p&gt;I have been implementing the SRv6 Mobile User Plane (RFC 9433) behaviors in the Linux kernel, and I am measuring them with &lt;a href="https://github.com/SRouting/SRPerf"&gt;SRPerf&lt;/a&gt; to see whether they keep up with the existing SRv6 behaviors. SRPerf is the measurement framework from the paper &lt;a href="https://doi.org/10.1109/TNSM.2020.3048328"&gt;SRPerf: A Performance Evaluation Framework for IPv6 Segment Routing&lt;/a&gt;, which benchmarked the SRv6 behaviors of Linux and VPP. The published version targets an older environment, so I use &lt;a href="https://github.com/higebu/SRPerf/tree/f91e3cd0508e47905df7e2f04c83ae1085a50f12"&gt;my fork&lt;/a&gt;, updated to run on Ubuntu 24.04 and Python 3.12.&lt;/p&gt;
&lt;p&gt;The paper says that H.Encaps gets slower if the tunnel source address (tunsrc) is not configured. It does not say how much slower, so I measured it.&lt;/p&gt;
&lt;h2 id="what-the-srperf-paper-says-about-tunsrc"&gt;What the SRPerf paper says about TUNSRC&lt;/h2&gt;
&lt;p&gt;The description of the experimental setup in the paper reads:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We configured the TUNSRC for the SRv6 policy headend behaviors doing encapsulation. The latter allows to configure the IPv6 source address of the IPv6 outer header. The TUNSRC has to be configured otherwise the Linux kernel will try to get the address from the interface which will cause a performance drop in the performance of the encaps behavior.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The authors measured with tunsrc configured, but the paper gives no number for the drop. Note that the published SRPerf &lt;a href="https://github.com/SRouting/SRPerf/blob/5bfab74a0b509f86406b0a306418629ed3e6e5d3/sut/linux/forwarding-behaviour.cfg"&gt;&lt;code&gt;forwarding-behaviour.cfg&lt;/code&gt;&lt;/a&gt; does not configure tunsrc, so you need to add it yourself to measure under the same conditions as the paper.&lt;/p&gt;
&lt;h2 id="what-happens-without-tunsrc"&gt;What happens without tunsrc&lt;/h2&gt;
&lt;p&gt;The source address of the outer IPv6 header is chosen by &lt;code&gt;set_tun_src()&lt;/code&gt; in &lt;code&gt;net/ipv6/seg6_iptunnel.c&lt;/code&gt; (&lt;a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv6/seg6_iptunnel.c?h=v7.1"&gt;v7.1 source&lt;/a&gt;).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;route_tunsrc&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;ipv6_addr_any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;route_tunsrc&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;memcpy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;route_tunsrc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;in6_addr&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;rcu_read_lock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tun_src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;rcu_dereference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sdata&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;tun_src&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;ipv6_addr_any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tun_src&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;memcpy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tun_src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;in6_addr&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;ipv6_dev_get_saddr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;daddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;IPV6_PREFER_SRC_PUBLIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;saddr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The kernel looks at the per-route tunsrc (since Linux 7.1) and then the per-network-namespace tunsrc (the one set with &lt;code&gt;ip sr tunsrc set&lt;/code&gt;). If both are &lt;code&gt;::&lt;/code&gt;, it calls &lt;code&gt;ipv6_dev_get_saddr()&lt;/code&gt;. tunsrc defaults to &lt;code&gt;::&lt;/code&gt;, so unless you configure it, the kernel compares the addresses on the host against the RFC 6724 rules for every packet. This is what the paper means by &amp;ldquo;the Linux kernel will try to get the address from the interface&amp;rdquo;.&lt;/p&gt;
&lt;h2 id="measuring-with-and-without-tunsrc"&gt;Measuring with and without tunsrc&lt;/h2&gt;
&lt;p&gt;I followed the paper&amp;rsquo;s method: the SUT (the machine under test) forwards on a single core, and I measured PDR (Partial Drop Rate, the highest offered rate with at most 0.5% packet loss) and MRR (Maximum Receive Rate, the receive rate when sending at line rate), 10 runs of 10 seconds each. The SUT has a Xeon E5-2650 v3 (2.30 GHz) and is directly connected to the tester running T-Rex with Intel 82599ES (10GbE) NICs. The IOMMU is in passthrough mode (&lt;code&gt;iommu=pt&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;With the same kernel and the same configuration, I only switched tunsrc between &lt;code&gt;::&lt;/code&gt; and &lt;code&gt;12:2::2&lt;/code&gt;. &lt;code&gt;12:2::2&lt;/code&gt; is the address the kernel picks when tunsrc is &lt;code&gt;::&lt;/code&gt;, so the only difference between the two runs is how the source address is chosen. For comparison, I also measured plain IPv6 and H.Insert (inline), which do not build an outer IPv6 header and therefore never reach &lt;code&gt;set_tun_src()&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;without tunsrc&lt;/th&gt;
&lt;th&gt;with tunsrc&lt;/th&gt;
&lt;th&gt;change&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;plain IPv6&lt;/td&gt;
&lt;td&gt;1196.0&lt;/td&gt;
&lt;td&gt;1192.2&lt;/td&gt;
&lt;td&gt;-0.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H.Insert&lt;/td&gt;
&lt;td&gt;998.3&lt;/td&gt;
&lt;td&gt;1001.3&lt;/td&gt;
&lt;td&gt;+0.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H.Encaps.V6&lt;/td&gt;
&lt;td&gt;569.8&lt;/td&gt;
&lt;td&gt;967.2&lt;/td&gt;
&lt;td&gt;+69.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H.Encaps.L2&lt;/td&gt;
&lt;td&gt;445.2&lt;/td&gt;
&lt;td&gt;656.2&lt;/td&gt;
&lt;td&gt;+47.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;(MRR, kpps)&lt;/p&gt;
&lt;p&gt;plain IPv6 and H.Insert barely moved, and only the two encap behaviors improved. Without tunsrc, H.Encaps.V6 was 41% slower and H.Encaps.L2 was 32% slower. H.Encaps.L2 also has a separate slowdown unrelated to tunsrc, and these numbers were taken on a kernel without that fix (I wrote about it in &lt;a href="https://www.higebu.com/en/blog/2026/10/01/srv6-l2encap/"&gt;the next post&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Converting PDR to cycles per packet (2.30 GHz / PDR), the difference is 1660 to 1670 cycles for both H.Encaps.V6 and H.Encaps.L2, which is the cost of the source address selection alone. This cost may depend on how many addresses the host has, which I did not measure.&lt;/p&gt;
&lt;p&gt;With tunsrc configured, H.Encaps.V6 reached a PDR of 976 kpps, almost the same as the 978 kpps in the paper.&lt;/p&gt;
&lt;h2 id="how-to-configure-tunsrc"&gt;How to configure tunsrc&lt;/h2&gt;
&lt;p&gt;With iproute2:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# per network namespace&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ip sr tunsrc &lt;span class="nb"&gt;set&lt;/span&gt; 2001:db8::1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ip sr tunsrc show
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# per route (Linux 7.1 and iproute2 7.1 or later)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ip -6 route add 2001:db8:100::/64 encap seg6 mode encap tunsrc 2001:db8::1 segs fc00::1 dev eth0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With FRR, put the following in the configuration (&lt;code&gt;frr.conf&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;segment-routing
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; srv6
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; encapsulation
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; source-address 2001:db8::1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;FRR does not set tunsrc unless &lt;code&gt;source-address&lt;/code&gt; is configured. I checked this by starting FRR: with only an SRv6 locator configured, &lt;code&gt;ip sr tunsrc show&lt;/code&gt; stayed at &lt;code&gt;::&lt;/code&gt;, and after adding &lt;code&gt;source-address&lt;/code&gt; it showed that address. bgpd&amp;rsquo;s SRv6 L3VPN does not set a per-route source address either, so without &lt;code&gt;source-address&lt;/code&gt; you get the slower path.&lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A. Abdelsalam, P. L. Ventre, C. Scarpitta, A. Mayer, S. Salsano, P. Camarillo, F. Clad, C. Filsfils, &amp;ldquo;&lt;a href="https://doi.org/10.1109/TNSM.2020.3048328"&gt;SRPerf: A Performance Evaluation Framework for IPv6 Segment Routing&lt;/a&gt;&amp;rdquo;, IEEE Transactions on Network and Service Management, vol. 18, no. 2, pp. 2320-2333, 2021&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/SRouting/SRPerf"&gt;SRPerf&lt;/a&gt; (GitHub) and &lt;a href="https://github.com/higebu/SRPerf/tree/f91e3cd0508e47905df7e2f04c83ae1085a50f12"&gt;my fork&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc8986.html"&gt;RFC 8986: Segment Routing over IPv6 (SRv6) Network Programming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc9433.html"&gt;RFC 9433: Segment Routing over IPv6 for the Mobile User Plane&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc6724.html"&gt;RFC 6724: Default Address Selection for Internet Protocol Version 6 (IPv6)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv6/seg6_iptunnel.c?h=v7.1"&gt;Linux v7.1 net/ipv6/seg6_iptunnel.c&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.frrouting.org/en/latest/zebra.html#clicmd-source-address-X-X-X-X"&gt;FRR User Guide: Zebra, SRv6 source-address&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>VMFork using mob</title><link>https://www.higebu.com/en/blog/2016/04/27/2016-04-27-vmfork-using-mob/</link><pubDate>Wed, 27 Apr 2016 23:57:00 +0000</pubDate><guid>https://www.higebu.com/en/blog/2016/04/27/2016-04-27-vmfork-using-mob/</guid><description>&lt;p&gt;We cannot do VMFork without &lt;a href="https://labs.vmware.com/flings/powercli-extensions"&gt;PowerCLI Extension&lt;/a&gt; for now. But that means there are VMFork related APIs in vSphere API.&lt;/p&gt;
&lt;p&gt;I explored those APIs using the MOB(The Managed Object Browser). Then I found it and I understand how to use it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer: VMFork is not officially supported by VMware, please use at your own risk.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="vmfork-related-apis"&gt;VMFork related APIs&lt;/h2&gt;
&lt;p&gt;There are following methods in VirtualMachine object.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CreateForkChild_Task&lt;/li&gt;
&lt;li&gt;EnableForkParent_Task&lt;/li&gt;
&lt;li&gt;DisableForkParent_Task&lt;/li&gt;
&lt;li&gt;RetrieveForkChildren_Task&lt;/li&gt;
&lt;li&gt;RetrieveForkParent_Task&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, there are &lt;code&gt;config.forkconfiginfo&lt;/code&gt; and &lt;code&gt;runtime.quiescedforkparent&lt;/code&gt; in VirtualMachine properties.&lt;/p&gt;
&lt;p&gt;These methods and properties are found in the HTML source of VM page on the MOB.&lt;/p&gt;
&lt;p&gt;This time, we want to run the VMFork, so we use &lt;code&gt;EnableForkParent_Task&lt;/code&gt; and &lt;code&gt;CreateForkChild_Task&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="how-to-run-the-vmfork-using-the-mob"&gt;How to run the VMFork using the MOB.&lt;/h2&gt;
&lt;h3 id="1-open-the-mob"&gt;1. Open the MOB.&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;https://&amp;lt;vcenter_ip_or_hostname&amp;gt;/mob/
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="2-open-the-virtualmachine-you-want-to-use-as-parent-vm"&gt;2. Open the VirtualMachine you want to use as parent VM.&lt;/h3&gt;
&lt;p&gt;Open the parent VM with using rootFolder or searchIndex. The URL would be like here.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;https://&amp;lt;vcenter_ip_or_hostname&amp;gt;/mob/?moid=&amp;lt;your_vm_moid&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="3-run-enableforkparent_task"&gt;3. Run EnableForkParent_Task&lt;/h3&gt;
&lt;p&gt;Open following URL.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;https://&amp;lt;vcenter_ip_or_hostname&amp;gt;/mob/?moid=&amp;lt;your_vm_moid&amp;gt;&amp;amp;method=enableForkParent
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This method has no parameters, you have only to click &lt;code&gt;Invoke Method&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="4-quiesce-the-parent-vm"&gt;4. Quiesce the parent VM&lt;/h3&gt;
&lt;p&gt;Run this command on the parent VM via console or SSH.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vmtoolsd --cmd &lt;span class="s1"&gt;&amp;#39;vmfork-begin -1 -1&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you want to automate it, you can use &lt;a href="https://pubs.vmware.com/vsphere-60/topic/com.vmware.wssdk.apiref.doc/vim.vm.guest.GuestOperationsManager.html#field_detail"&gt;GuestOperationsManager&lt;/a&gt;.ProcessManager.&lt;/p&gt;
&lt;p&gt;PowerCLI&amp;rsquo;s &lt;code&gt;Enable-InstantCloneVM&lt;/code&gt; upload PreQuiesceScript and PostCloneScript with operations up to this point.&lt;/p&gt;
&lt;p&gt;You can upload these scripts with &lt;a href="https://pubs.vmware.com/vsphere-60/topic/com.vmware.wssdk.apiref.doc/vim.vm.guest.GuestOperationsManager.html#field_detail"&gt;GuestOperationsManager&lt;/a&gt; instead of PowerCLI.&lt;/p&gt;
&lt;p&gt;Also, It seems that PowerCLI&amp;rsquo;s &lt;code&gt;Enable-InstantCloneVM&lt;/code&gt; runs PreQuiesceScript and PostCloneScript with &lt;a href="https://pubs.vmware.com/vsphere-60/topic/com.vmware.wssdk.apiref.doc/vim.vm.guest.GuestOperationsManager.html#field_detail"&gt;GuestOperationsManager&lt;/a&gt;. The command is like here.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$prescript_path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;vmtoolsd --cmd &lt;span class="s1"&gt;&amp;#39;vmfork-begin -1 -1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nv"&gt;$postscript_path&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="5-run-vmfork"&gt;5. Run VMFork&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;CreateForkChild_Task&lt;/code&gt;. It is same as PowerCLI&amp;rsquo;s &lt;code&gt;New-InstantCloneVM&lt;/code&gt;. The URL is following.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;https://&amp;lt;vcenter_ip_or_hostname&amp;gt;/mob/?moid=&amp;lt;your_vm_moid&amp;gt;&amp;amp;method=createForkChild
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;CreateForkChild_Task&lt;/code&gt; has parameters, &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;spec&lt;/code&gt;. &lt;code&gt;name&lt;/code&gt; is child VM name. And I guess &lt;code&gt;spec&lt;/code&gt; is &lt;a href="https://www.vmware.com/support/developer/converter-sdk/conv61_apireference/vim.vm.CreateChildSpec.html"&gt;VirtualMachineCreateChildSpec&lt;/a&gt;. Minimun &lt;code&gt;spec&lt;/code&gt; is here.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;spec&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;persistent&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/persistent&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/spec&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Click &lt;code&gt;Invoke Method&lt;/code&gt;. The child VM will be created in an instant.&lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blogs.vmware.com/PowerCLI/2015/08/vmware-instant-clone-now-fingertips-new-powercli-extensions-fling.html"&gt;VMware Instant Clone is now at your fingertips with the updated PowerCLI Extensions fling!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.virtuallyghetto.com/2015/08/instant-clone-powercli-cmdlets-best-practices-troubleshooting.html"&gt;Instant Clone PowerCLI cmdlets Best Practices &amp;amp; Troubleshooting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.virtuallyghetto.com/2015/08/how-to-vmfork-aka-instant-clone-nested-esxi.html"&gt;How to VMFork aka Instant Clone Nested ESXi?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/lamw/vmfork-community-customization-scripts"&gt;lamw/vmfork-community-customization-scripts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/vmware/vic"&gt;vSphere Integrated Containers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://communities.vmware.com/docs/DOC-11670"&gt;How to browse the internal vSphere APIs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>vSphere Client 5.5 on Ubuntu 14.04</title><link>https://www.higebu.com/en/blog/2015/03/15/vsphere-client-on-ubuntu/</link><pubDate>Sun, 15 Mar 2015 12:30:00 +0000</pubDate><guid>https://www.higebu.com/en/blog/2015/03/15/vsphere-client-on-ubuntu/</guid><description>&lt;h2 id="versions"&gt;Versions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Ubuntu 14.04.2 amd64&lt;/li&gt;
&lt;li&gt;wine 1.7.38&lt;/li&gt;
&lt;li&gt;mono 4.5.4&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="install-wine-and-net"&gt;Install Wine and .NET&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Run following commands:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo add-apt-repository ppa:ubuntu-wine/ppa
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get install -y wine1.7 wine-mono4.5.4 wine-gecko2.34
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Confirm Wine version&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ wine --version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wine-1.7.38
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Set up 32bit Wine&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;WINEARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;win32 &lt;span class="nv"&gt;WINEPREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/.wine32 winecfg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Install .NET&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;WINEARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;win32 &lt;span class="nv"&gt;WINEPREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/.wine32 winetricks dotnet20
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;WINEARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;win32 &lt;span class="nv"&gt;WINEPREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/.wine32 winetricks dotnet30
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;WINEARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;win32 &lt;span class="nv"&gt;WINEPREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/.wine32 winetricks dotnet20sp1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;WINEARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;win32 &lt;span class="nv"&gt;WINEPREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/.wine32 winetricks dotnet30sp1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;WINEARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;win32 &lt;span class="nv"&gt;WINEPREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/.wine32 winetricks dotnet35
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;WINEARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;win32 &lt;span class="nv"&gt;WINEPREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/.wine32 winetricks dotnet35sp1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the above commands exits with error, and shows a download url. Download the file and put into specified directory.&lt;/p&gt;
&lt;h2 id="install-vsphere-client"&gt;Install vSphere Client&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Download vSphere Client Installer, and run following command:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;WINEARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;win32 &lt;span class="nv"&gt;WINEPREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/.wine32 wine Downloads/VMware-viclient-all-5.5.0-1993072.exe
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="run-vsphere-client"&gt;Run vSphere Client&lt;/h2&gt;
&lt;p&gt;Run following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;WINEARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;win32 &lt;span class="nv"&gt;WINEPREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.wine32 wine &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.wine32/drive_c/Program&lt;span class="se"&gt;\ &lt;/span&gt;Files/VMware/Infrastructure/Virtual&lt;span class="se"&gt;\ &lt;/span&gt;Infrastructure&lt;span class="se"&gt;\ &lt;/span&gt;Client/Launcher/VpxClient.exe
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or double click the shortcut on your desktop.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.higebu.com/images/20150315-vsphere-client.png" alt="vsphere-client"&gt;
Console doesn&amp;rsquo;t work now. If you want to use console, you should use VMware Workstation or VNC.&lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.winehq.org/"&gt;Wine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://atmosphere147.blogspot.jp/2014/05/how-to-install-vsphere-client-55-on-mac.html"&gt;How to install vSphere Client 5.5 on Mac OSX using Wine&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>