<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Donatas Abraitis</title>
    <description></description>
    <link>https://donatas.net/</link>
    <atom:link href="https://donatas.net/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Wed, 29 Apr 2026 11:28:53 +0000</pubDate>
    <lastBuildDate>Wed, 29 Apr 2026 11:28:53 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Scaling Chef Server</title>
        <description>&lt;p&gt;If you search on how to scale Chef Server, you are lucky, there is a &lt;a href=&quot;http://irvingpop.github.io/blog/2015/04/20/tuning-the-chef-server-for-scale/&quot;&gt;SINGLE&lt;/a&gt; post in internets.
I appreciate the author of this blog post which helped me go in the right direction (moving from standalone instance to multiple).&lt;/p&gt;

&lt;p&gt;I’m gonna switch into German mode here and wanna give a big disappointment for Chef Community: it’s horrible, lack of proper documentation, authors of Chef suggesting do not use Chef (=huh?) or paying money - helpless, at all. Unlike Ansible. But let’s leave this topic untouched here.&lt;/p&gt;

&lt;p&gt;Standalone Chef Server served well for a long time until reached more than 700 nodes with heavy searches and a non-optimized version of cookbooks. Scaling vertically was good
enough until around 1000 nodes. It was kinda 4 CPU cores, later 8, 16, 32, and we are done here. Chef Server is CPU intensive, memory does not matter much.&lt;/p&gt;

&lt;p&gt;The main CPU hungry process is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;erchef&lt;/code&gt; which is responsible for serving API requests for all necessary components: search, cookbooks, nodes, attributes, etc.&lt;/p&gt;

&lt;p&gt;Then we start looking at the beforementioned blog post tuning recommendations, like enable cookbook caching, worker count tuning, timeouts, etc. Frankly speaking, it doesn’t help at all if you reach this state with 32 cores going at full rate.&lt;/p&gt;

&lt;p&gt;I was randomly reminded about when it should be the time to start scaling this horizontally because one day shit could happen (When it’s most needed - rule of thumb).&lt;/p&gt;

&lt;p&gt;We run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chef-client&lt;/code&gt; every 30min. + 15min. of splay time.&lt;/p&gt;

&lt;p&gt;First, what you have to do is eliminate all possible &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*:*&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name:*&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fqdn:*&lt;/code&gt; or any other wildcard searches in your recipes. This is basically handled in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;erchef&lt;/code&gt; which is as I said before CPU-hungry. That means, you fetch all attributes from PostgreSQL (backend) and parse them in Erlang. Instead of fetching from Solr (already chewed).
In our case queries like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fqdn:*&lt;/code&gt; eat 16 cores (nice and easy).&lt;/p&gt;

&lt;p&gt;The next step was to replace all &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;search()&lt;/code&gt; calls with &lt;a href=&quot;https://docs.chef.io/chef_search/#filter-search-results&quot;&gt;filtered&lt;/a&gt; searches. That reduces the load for the erchef process and overall.&lt;/p&gt;

&lt;p&gt;One more thing to consider is to review all possible iterations through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data_bag_item()&lt;/code&gt; and replace it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;search(:something, &apos;id:*&apos;)&lt;/code&gt;. Erchef does not like this much, but eventually, it’s good enough.&lt;/p&gt;

&lt;p&gt;Before optimizations, we had converged time around 15-30min. It depends on the location. We had Geo distributed nodes with a single Chef Server in Europe while nodes are everywhere: US, SG, BR, ID, everywhere.&lt;/p&gt;

&lt;p&gt;After optimizations converge time dropped to 5-20min. or so. Well, almost half-cut. Not bad, not good.&lt;/p&gt;

&lt;p&gt;But still, there are searches that can’t be replaced for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fqdn:*&lt;/code&gt; due to limitations in our infrastructure. Erchef is still angry about that. Decided to replace our standalone Chef Server with tiered architecture. One backend and multiple frontend servers. Two frontends per location with anycast for load balancing and high availability.&lt;/p&gt;

&lt;p&gt;Backup standalone Chef Server instance and do restore on new frontends. That’s it, you need to change configs only afterward.&lt;/p&gt;

&lt;p&gt;This is the graph (CPU drop) after launched frontend servers. Erchef is happy as never before.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/chef-server.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chef-client&lt;/code&gt; converge time dropped noticeably.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/chef-client.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Still, the problem is that frontends are scaled per region while the backend is single (especially PostgreSQL). From Singapore to UK or so, latency is around 160-300ms, it depends on the conditions how the traffic is routed. We had a problem with one of our ISPs in Singapore and download bandwidth dropped below 1Mbps. And guess what. The chef stopped working at all, every queries to the backend timed out. When this happens, even 10s timeout is not enough. The biggest problem was due to (again) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fqdn:*&lt;/code&gt; searches which consume sort of &lt;em&gt;more&lt;/em&gt; traffic and causes timeouts. For non-wildcards queries that were basically good enough if the response size was around 100Kb.&lt;/p&gt;

&lt;p&gt;Started thinking quickly about what to do here. Decided to launch &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pgpool-II&lt;/code&gt; instances as a sidecar to Chef frontends and separate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;memcached&lt;/code&gt; instances per region to cache data from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pgpool-II&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Cache hit ratio to memcached instances isn’t high, around 10%, but that’s enough to offload wildcard searches.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/chef-client-after-memcached.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And now, we have converge time dropped to 1-5min.&lt;/p&gt;

&lt;p&gt;The traffic to the backend server from frontends dropped by half from ~500mbps to ~250mbps.&lt;/p&gt;

&lt;h4 id=&quot;fin&quot;&gt;FIN&lt;/h4&gt;

&lt;p&gt;I hope this post will be handy for others looking for similar problems.&lt;/p&gt;

&lt;h4 id=&quot;bonus---pgpoolconf&quot;&gt;Bonus - pgpool.conf&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;listen_addresses = &apos;localhost&apos;
port = 31337
socket_dir = &apos;/tmp&apos;
listen_backlog_multiplier = 2
pcp_listen_addresses = &apos;localhost&apos;
pcp_port = 9898
pcp_socket_dir = &apos;/tmp&apos;
backend_hostname0 = &apos;chef-backend.donatas.net&apos;
backend_port0 = 5432
enable_pool_hba = off
pool_passwd = &apos;something&apos;
authentication_timeout = 120
num_init_children = 32
max_pool = 16
child_life_time = 900
child_max_connections = 1000
connection_life_time = 600
pid_file_name = &apos;/var/run/pgpool/pgpool.pid&apos;
logdir = &apos;/var/log/pgpool&apos;
connection_cache = on
memory_cache_enabled = on
memqcache_method = &apos;memcached&apos;
memqcache_memcached_host = &apos;chef-memcached.donatas.net&apos;
memqcache_memcached_port = 11211
memqcache_total_size = 134217728
memqcache_max_num_cache = 10000000
memqcache_expire = 14400
memqcache_auto_cache_invalidation = on
memqcache_maxcache = 1048576
memqcache_cache_block_size = 2097152
memqcache_oiddir = &apos;/var/log/pgpool/oiddir&apos;
white_memqcache_table_list = &apos;&apos;
black_memqcache_table_list = &apos;&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;bonus---frontend-config&quot;&gt;Bonus - frontend config&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;nginx[&apos;enable_ipv6&apos;] = true
nginx[&apos;ssl_certificate&apos;] = &apos;/var/opt/opscode/nginx/ca/donatas.net.crt&apos;
nginx[&apos;ssl_certificate_key&apos;] = &apos;/var/opt/opscode/nginx/ca/donatas.net.key&apos;
opscode_erchef[&apos;depsolver_worker_count&apos;] = 8
opscode_expander[&apos;nodes&apos;] = 8
opscode_erchef[&apos;nginx_bookshelf_caching&apos;] = &apos;:on&apos;
opscode_erchef[&apos;s3_url_expiry_window_size&apos;] = &apos;100%&apos;
opscode_erchef[&apos;db_pool_queue_max&apos;] = 32
opscode_erchef[&apos;db_pooler_timeout&apos;] = 300000
opscode_erchef[&apos;depsolver_pool_queue_max&apos;] = 10
opscode_erchef[&apos;depsolver_pooler_timeout&apos;] = 300000
opscode_erchef[&apos;db_pool_size&apos;] = 16
opscode_erchef[&apos;sql_db_timeout&apos;] = 300000
opscode_erchef[&apos;authz_timeout&apos;] = 300000
oc_bifrost[&apos;db_pooler_timeout&apos;] = 300000
oc_bifrost[&apos;db_pool_queue_max&apos;] = 32
oc_bifrost[&apos;db_pool_size&apos;] = 16
lb[&apos;cache_cookbook_files&apos;] = true
lb[&apos;redis_connection_timeout&apos;] = 300000
lb[&apos;redis_keepalive_timeout&apos;] = 300000
postgresql[&apos;vip&apos;] = &apos;127.0.0.1&apos;
postgresql[&apos;port&apos;] = 31337

topology &apos;tier&apos;

server &apos;backend1.donatas.net&apos;,
  :ipaddress =&amp;gt; &apos;X.X.X.X&apos;,
  :role =&amp;gt; &apos;backend&apos;,
  :bootstrap =&amp;gt; true

backend_vip &apos;backend1.donatas.net&apos;,
  :ipaddress =&amp;gt; &apos;X.X.X.X,
  :device =&amp;gt; &apos;ens192&apos;

server &apos;frontend1.donatas.net&apos;,
  :ipaddress =&amp;gt; &apos;Y.Y.Y.1&apos;,
  :role =&amp;gt; &apos;frontend&apos;

server &apos;frontend2.donatas.net&apos;,
  :ipaddress =&amp;gt; &apos;Y.Y.Y.2&apos;,
  :role =&amp;gt; &apos;frontend&apos;

server &apos;frontend3.donatas.net&apos;,
  :ipaddress =&amp;gt; &apos;Y.Y.Y.3&apos;,
  :role =&amp;gt; &apos;frontend&apos;

server &apos;frontend4.donatas.net&apos;,
  :ipaddress =&amp;gt; &apos;Y.Y.Y.4&apos;,
  :role =&amp;gt; &apos;frontend&apos;

...

api_fqdn &apos;chef.donatas.net&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Fri, 26 Mar 2021 00:00:00 +0000</pubDate>
        <link>https://donatas.net/blog/2021/03/26/scaling-chef-server/</link>
        <guid isPermaLink="true">https://donatas.net/blog/2021/03/26/scaling-chef-server/</guid>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>Unnecessary Updates in BGP</title>
        <description>&lt;p&gt;It is well known that BGP, as a distance-vector protocol, suffers from path exploration: For every withdrawn route (AS path or any other mandatory attribute change), the next best, supposedly valid route is selected and announced, until there are no more candidates left in the router’s RIB.&lt;/p&gt;

&lt;p&gt;BGP routers can generate multiple identical announcements with empty community attributes if stripped at egress. This is an undesired behavior. Why do we need to send an UPDATE if this is not an actual change?&lt;/p&gt;

&lt;p&gt;Imagine a topology below:
&lt;img src=&quot;/images/bgp-unnecessary-updates.png&quot; alt=&quot;BGP Unnecessary Updates&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Assume a converged network. In order to induce updates for prefix &lt;em&gt;p&lt;/em&gt;, we disable the link between Y1 and Y2 and wait for arriving updates at collector C1.&lt;/p&gt;

&lt;p&gt;I have FRRouting configuration at X1:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;router bgp 65002
  no bgp ebgp-requires-policy
  neighbor 10.0.1.1 remote-as external
  neighbor 10.0.1.1 timers 3 10
  neighbor 10.0.2.2 remote-as external
  neighbor 10.0.2.2 timers 3 10
  address-family ipv4 unicast
    redistribute connected
    neighbor 10.0.1.1 route-map c1 out
  exit-address-family
!
bgp community-list standard c1 seq 1 permit 65004:2
bgp community-list standard c1 seq 2 permit 65004:3
!
route-map c1 permit 10
  set comm-list c1 delete
!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;X1 receives paths with communities 65004:2 and 65004:3 from Y1 because those paths are tagged at Y2 and Y3 appropriately.&lt;/p&gt;

&lt;p&gt;When X1 sends the best path to C1 it generates duplicate updates because of attribute change (community, 65004:2 -&amp;gt; 65004:3). But since we strip all communities at egress, it’s absolutely not necessary sending duplicates towards C1 because the Adj-Rib-Out wasn’t changed.&lt;/p&gt;

&lt;p&gt;I developed a &lt;a href=&quot;https://github.com/FRRouting/frr/pull/7507&quot;&gt;patch&lt;/a&gt; for FRRouting, which prevents sending duplicate updates if the path actually not changed. This is valid for all attributes.&lt;/p&gt;

&lt;p&gt;For more detailed information and experiments, please read at &lt;a href=&quot;https://www.cmand.org/communityexploration/&quot;&gt;https://www.cmand.org/communityexploration/&lt;/a&gt;. You will find more configuration examples for other routers (Cisco, Juniper, Nokia) and other software routing daemons (Bird, OpenBGPD, Quagga).&lt;/p&gt;
</description>
        <pubDate>Sun, 29 Nov 2020 00:00:00 +0000</pubDate>
        <link>https://donatas.net/blog/2020/11/29/unnecessary-updates-bgp/</link>
        <guid isPermaLink="true">https://donatas.net/blog/2020/11/29/unnecessary-updates-bgp/</guid>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>ARP table quiz in Cumulus Linux</title>
        <description>&lt;p&gt;The weird situation when you notice that IPv4 get a packet loss, while IPv6 works as expected for the same physical link:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;--- 2a02:4780:face:f00d::1 ping statistics ---
1368 packets transmitted, 1368 received, 0% packet loss, time 1367006ms
rtt min/avg/max/mdev = 0.217/0.285/0.667/0.045 ms
root@sg-nme-leaf1:~#

--- 10.0.31.1 ping statistics ---
1366 packets transmitted, 1348 received, 1% packet loss, time 1365005ms
rtt min/avg/max/mdev = 0.147/0.227/0.874/0.064 ms
root@sg-nme-leaf1:~#
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There is a lot of what to check, but this is what I did solving this issue.&lt;/p&gt;

&lt;p&gt;First I checked &lt;a href=&quot;https://docs.cumulusnetworks.com/cumulus-linux-41/Layer-1-and-Switch-Ports/Prescriptive-Topology-Manager-PTM/&quot;&gt;ptmd&lt;/a&gt; status which surprised me more. BFD status was failed, but
BGP session was UP. That’s because we use a single IPv6 session for both IPv4 and IPv6.&lt;/p&gt;

&lt;p&gt;10.0.31.1 is down while 2a02:4780:face:f00d::1 is up. Why? It’s for the same reason (packet loss).&lt;/p&gt;

&lt;p&gt;Checking for drops/errors with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethtool -S swp48 | grep -iE &quot;drop|err|disc&quot;&lt;/code&gt; gave nothing except that there is a usual drops count which is normal due ACL, bursty buffer congestions, etc.&lt;/p&gt;

&lt;p&gt;If IPv6 works while IPv4 not, it seems related to the ARP table. I double-checked ARP table entries with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ip neigh | wc -l&lt;/code&gt;. It was around 6k. Nothing special as well, just a well-worn node.&lt;/p&gt;

&lt;p&gt;Unfortunately, Broadcom devices do not have native ASIC monitoring, which could provide me with the stats about the buffers, packets count, queue lengths, etc.&lt;/p&gt;

&lt;p&gt;I thought I would inspect buffer congestions or so, but anyway. Continuing.&lt;/p&gt;

&lt;p&gt;Running this command in a terminal I noticed host entries drop when packet loss happens:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;watch -n 1 &apos;date &amp;gt;&amp;gt; /tmp/host_count.log ; cat /cumulus/switchd/run/route_info/host/count_0 &amp;gt;&amp;gt; /tmp/host_count.log ; tail /tmp/host_count.log&apos;

Fri Jul 17 08:14:06 UTC 2020
12702
Fri Jul 17 08:14:07 UTC 2020
9281
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Like from 12k to 9k and varying. The maximum is 16k, but that’s not an issue since it’s not hitting nearly 16k.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dmesg&lt;/code&gt; is clear. If it would be garbage collection for a stale ARP entries it would be an error message in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dmesg&lt;/code&gt; output, like: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel: Neighbour table overflow&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Just in case I checked &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net.ipv4.neigh.default.gc_thresh1&lt;/code&gt; which was a default 128. Like I mentioned above current ARP entries were around 6k.&lt;/p&gt;

&lt;p&gt;128 is the maximum number of ARP entries in the cache. Garbage collection won’t be triggered if below 128. We have 6k. That’s why I noticed a host entries drop when packet loss happens. I double-checked this few times and confirmed.&lt;/p&gt;

&lt;p&gt;Lowered gc_thresh1 to slightly less than we have ARP entries fixed the problem.&lt;/p&gt;

&lt;p&gt;If you raise gc_thresh1 higher than you have entries, you will probably gonna have lots of FAILED/STALE entries in the neighbor
table and fun things could start happening (lots of TCP spurious retransmissions, out of order packets, and so on).&lt;/p&gt;

&lt;p&gt;So keep eyes carefully on this ;-)&lt;/p&gt;
</description>
        <pubDate>Fri, 17 Jul 2020 00:00:00 +0000</pubDate>
        <link>https://donatas.net/blog/2020/07/17/arp-table-quiz-in-cumulus-linux/</link>
        <guid isPermaLink="true">https://donatas.net/blog/2020/07/17/arp-table-quiz-in-cumulus-linux/</guid>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>Two years in FRRouting</title>
        <description>&lt;p&gt;Since the beginning of my contribution to &lt;a href=&quot;https://frrouting.org/&quot;&gt;FRRouting&lt;/a&gt;, I raised myself to the top 15 contributors (that’s a huge win for me personally):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;% git shortlog --summary --numbered | head -n15
  4713    Donald Sharp
  1712    Quentin Young
  1674    David Lamparter
  1108    Renato Westphal
   791    paul
   545    Philippe Guibert
   522    Lou Berger
   518    Russ White
   464    Paul Jakma
   446    Rafael Zalamena
   409    Mark Stapp
   388    Christian Franke
   387    Daniel Walton
   384    Martin Winter
   365    Donatas Abraitis
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now I feel that I can read the code, I can find the root causes faster, I can even review others’ code, not that dumb and green as was 2 years ago.&lt;/p&gt;

&lt;p&gt;When I started digging into FRRouting (because it was picked by Cumulus Networks) I solved old issues (3-4 years old), there were really lots of them. I managed to solve quite a lot, more to go still, but it’s never-ending for a huge and fast-moving project. Of course, I’m not referring &lt;a href=&quot;https://github.com/ansible/ansible/&quot;&gt;github.com/ansible/ansible&lt;/a&gt;, which is I would say brain dead.&lt;/p&gt;

&lt;p&gt;What I do now? I participate in the development process more and more. Mostly I contribute to BGP protocol (my favorite one), packaging, and testing environments. Sometimes in other areas (don’t have much experience and knowledge yet of other protocols).&lt;/p&gt;

&lt;p&gt;Overall my commits during two years (including merge commits of other contributors):&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;% git shortlog --summary --numbered --author=&apos;Donatas Abraitis&apos;
   365  Donatas Abraitis
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Commits owned by me:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;% git shortlog --summary --numbered --no-merges --author=&apos;Donatas Abraitis&apos;
   204  Donatas Abraitis
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Doing the math one commit every third day. For some people, I know that would be like a full-time job. Comparing with my regular work, two of the most active repositories I contribute are:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;% git shortlog --summary --numbered --no-merges --since=&quot;2 years ago&quot; --author=&apos;Donatas Abraitis&apos;
  1148  Donatas Abraitis

% git shortlog --summary --numbered --no-merges --since=&quot;2 years ago&quot; --author=&apos;Donatas Abraitis&apos;
   355  Donatas Abraitis
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That sounds like a full-time vs. a part-time job.&lt;/p&gt;

&lt;p&gt;I absolutely do not regret that I spent plenty of my free time contributing to FRRouting because that helped me grow as a person and professionally. Also, I started understanding lots of things about how huge open-source projects work, how the deployments run, communication, rules. Third home.&lt;/p&gt;

&lt;p&gt;I see that with more time you get more trust from the community, you get valued. At the beginning, I thought I’m very annoying and angry about reviewing others’ code, but it seems not, people value that.&lt;/p&gt;

&lt;p&gt;We just can’t push the bad code, which does not keep requirements, no documentation updates, and testing. That’s not a private project which is used by 10 people (what is usually seen in most companies). There is no excuse to push the bad or untested code.&lt;/p&gt;

&lt;p&gt;Basically, we are trying to keep requirements like Linux kernel does: checkpatch.pl, clang-formatter, etc.&lt;/p&gt;

&lt;p&gt;I remember one day I was tackling a &lt;a href=&quot;http://www.thekelleys.org.uk/dnsmasq/doc.html&quot;&gt;dnsmasq&lt;/a&gt; issue at &lt;a href=&quot;https://www.hostinger.com/&quot;&gt;Hostinger&lt;/a&gt; and wanna check how caching is implemented in dnsmasq because the performance comparing to &lt;a href=&quot;https://cr.yp.to/djbdns/tinydns.html&quot;&gt;tinydns&lt;/a&gt; is really significant (tinydns 10x faster).&lt;/p&gt;

&lt;p&gt;I pulled the source code to dig into the problem I was facing (not the scope of this blog post). Guess what was my first words (direct). “Abandoned university bachelor’s code.”
Yes, that’s the very very notable difference when you look at the code which is community-driven and which is just another one more project.&lt;/p&gt;

&lt;p&gt;How could it be better when you commit and even more maintain the world-class project which is used by such big players like Microsoft, Amazon, RedHat, VMWare, Cumulus Networks, etc.? Wait, Cumulus Networks acquired by &lt;a href=&quot;https://blogs.nvidia.com/blog/2020/05/04/nvidia-acquires-cumulus/&quot;&gt;NVIDIA&lt;/a&gt;, that complicates things even more :)&lt;/p&gt;

&lt;p&gt;My kids sometimes ask me, why do you work all the time? Well, I answer honestly that I’m not working, I’m learning. It’s my hobby, the same as you watching “Nastya”, “Roma and Diana”, “AcroYoga”, etc., riding a bike.&lt;/p&gt;

&lt;p&gt;Sometimes doing that at weekends, usually when I have nothing else planned to do. Don’t expect you doing that.&lt;/p&gt;

&lt;p&gt;I always think about leaving the project, but it’s hard, it’s like a third family, where you have an amazing community, good practices, super-hero developers, you just learn, you can’t leave your home :)&lt;/p&gt;

&lt;p&gt;This is not the same as a regular job, you don’t get money. But you kinda drive a project which is brilliant. Which is emotionally awesome.&lt;/p&gt;

&lt;p&gt;To sum up, being maintainer doesn’t mean you have to be pro-level in everything. I formed my opinion that it’s enough to be active, responsive, willing to help, learn a lot, dig very deep into the protocols, and of course going wild reading RFCs.&lt;/p&gt;
</description>
        <pubDate>Fri, 08 May 2020 00:00:00 +0000</pubDate>
        <link>https://donatas.net/blog/2020/05/08/two-years-in-frrouting/</link>
        <guid isPermaLink="true">https://donatas.net/blog/2020/05/08/two-years-in-frrouting/</guid>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>Became maintainer of FRRouting</title>
        <description>&lt;p&gt;This is the main reason I stopped (or less) blogging because I’m more interested in how the internet works and give my full fingers improving the internet overall.&lt;/p&gt;

&lt;p&gt;At first, it sounds amazing on the title. Yes, that’s really cool and motivating. Secondly, you have to pay more attention to what you do as a developer plus review others code where you have some degree to do it, continue reading the source code, help the community to adopt the product for their use.&lt;/p&gt;

&lt;p&gt;I started contributing to FRRouting open-source project around one and a half year ago. I just went over existing issues and tried reducing them (solving). In the beginning, I felt like I got a new job. Setup development environment, new tools, formaters, linters, strict requirements, similar to the Linux kernel’s workflow, etc. It was fun and I learned lots of really new stuff, met new especially very very smart people.&lt;/p&gt;

&lt;p&gt;After a year I was promoted being the maintainer of FRRouting project.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/frr-maintainer.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What does it mean?&lt;/p&gt;

&lt;p&gt;Maintaining a huge world-class project is a huge responsibility because you can quickly lose your trust. We have weekly virtual meetings to discuss the current issues, pull requests and then decide who takes which part or who will review something existing. We have Slack channels where discuss some only related things. No rush. It’s always better to have a slow loop rather than going through the fast loop and fixing things again and again.&lt;/p&gt;

&lt;p&gt;The lifespan the PR takes to be reviewed sometimes takes even months. Code reviewers have to actually look at the code, they can’t just hope the community will somehow perform a proper review. A project also cannot rely just on tools, they will never do the full job. Proper code review takes a lot of time, and it needs to be done by experienced developers.&lt;/p&gt;

&lt;p&gt;Responsibility comes when you have to review or fix parts you already changed/improved. I always had a fear of commenting, merging and discussing the stuff you are not the best one comparing with others. With time I became more comfortable being part of the project.&lt;/p&gt;

&lt;p&gt;Noticed an interesting issue and wanted trying it as a challenge? Let’s assign self and start the journey. Sometimes I have no clue if I can or can’t implement assigned issue at all, but it’s even more challenging than a regular job because you must write good code, you must keep styling, testing and other requirements in place. In regular jobs, you mostly can ignore that while here no. Comparing to a permanent job, code review could be more strict in open source projects because you have to keep all the things unified.&lt;/p&gt;

&lt;p&gt;Companies require to push features or bugfixes as fast as possible even without carrying about the performance, quality and other factors. Just push forward. In open-source, things differ. Your commits could stay even months not merged. And that’s normal. Why? Because of both: the quality and performance.&lt;/p&gt;

&lt;p&gt;My one of the favorite phrase Linus said:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;The New Linus: “I really like you as a person and all. But that code will only get committed over my dead body.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Again, maintaining a global project doesn’t mean you have full control and do what you want. For instance, implement BGP version capability, but it’s absolutely not worth doing this without published draft/RFC.&lt;/p&gt;

&lt;p&gt;So I created a &lt;a href=&quot;https://www.ietf.org/id/draft-abraitis-bgp-version-capability-01.txt&quot;&gt;draft&lt;/a&gt;, then we discussed in &lt;a href=&quot;https://mailarchive.ietf.org/arch/browse/idr&quot;&gt;IDR mailing&lt;/a&gt; list about all the options and culprits. Some were agreeing with me, some not, but it’s absolutely fine to be rejected eventually. However, writing draft/RFC is really not the funniest thing to do, because at first it must be written in XML, then you must pass the validations (syntax, grammar, paragraphs, references, etc.), discuss with the community if it’s worth, code a working example/prototype as a reference.&lt;/p&gt;

&lt;h3 id=&quot;fun-facts&quot;&gt;Fun facts&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Google (rumors that Facebook as well) uses FRRouting internally;&lt;/li&gt;
  &lt;li&gt;I was invited to a &lt;a href=&quot;https://teltonika.lt&quot;&gt;job interview&lt;/a&gt;, then I asked them why did you invite me? “We saw you are a maintainer of a project we use in our devices for routing”;&lt;/li&gt;
  &lt;li&gt;The best thing that happened apart from the birth of a child - huge motivation to move forward.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 04 Sep 2019 00:00:00 +0000</pubDate>
        <link>https://donatas.net/blog/2019/09/04/became-frrouting-maintainer/</link>
        <guid isPermaLink="true">https://donatas.net/blog/2019/09/04/became-frrouting-maintainer/</guid>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>LLDP does not work with i40ge driver in VMWare ESXi</title>
        <description>&lt;p&gt;Imagine your services critically depend on the Link Layer Discovery Protocol (LLDP). And this is the &lt;em&gt;brownie&lt;/em&gt; if you have $VMWare ESXi and Intel 710/711722 series NICs.&lt;/p&gt;

&lt;p&gt;LLDP just doesn’t work with i40ge driver well. Well, it doesn’t work at all.&lt;/p&gt;

&lt;p&gt;Test it on the guest:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# lldpctl
-------------------------------------------------------------------------------
LLDP neighbors:
-------------------------------------------------------------------------------
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The main problem is that the NIC doesn’t forward LLDP packets to guests. Hence, you can’t see what are your neighbors inside the guest. The bigger problem arises if you depend on LLDP and other services are failing due to that. Cascading failure scenario.&lt;/p&gt;

&lt;p&gt;To overcome this limitation and allow guests to see LLDP packets you MUST use the newest i40ge driver and modify the flash.&lt;/p&gt;

&lt;p&gt;Here are the commands to upgrade i40ge firmware to the newest and disable LLDP agent. When you disable LLDP agent, it will forward LLDP packets to guests:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# wget http://donatas.net/VMW-ESX-6.7.0-i40en-1.8.6-13636624.zip
# esxcli software vib install -v /vmfs/volumes/datastore1/__tmp/i40en-1.8.6-1OEM.670.0.0.8169922.x86_64.vib
# esxcli system module parameters list -m i40en
# esxcli system module parameters set -m i40en -p LLDP=0,0
# reboot
# wget http://donatas.net/x722-lldp.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;As you see from the output above, it’s not enough to upgrade the firmware. We need to use the 3rd party tool which is released by Lenovo to flash the firmware and disable LLDP agent.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[root@us-imm-esxi7:/vmfs/volumes/5cef6df8-fabe2ba4-7e68-ac1f6b5a176e/__tmp/X722-LLDP-FW-Setting-Tool/esxin64e] ./LLD
Pn64e -disable -debug
Connection to QV driver failed - please reinstall it!
LLDP 1.0.5
Copyright (C) 2018 Intel Corporation

Scanning for matching Intel(R) devices...

## Vend Dev  MAC          Branding-String
-- ---- ---- ------------ ---------------
MAC type is 327683
 1 8086 37D2 AC1F6B5A176E Intel(R) Ethernet Connection X722 for 10GBASE-T
   FW: 3033 ETrack: 80000E48  FW:3.1 API:1.5  NVM: 3.33 MAP2.31
MAC type is 327683
 2 8086 37D2 AC1F6B5A176F Intel(R) Ethernet Connection X722 for 10GBASE-T
   FW: 3033 ETrack: 80000E48  FW:3.1 API:1.5  NVM: 3.33 MAP2.31
-- ---- ---- ------------ ---------------

2 matching adapters discovered.

About to disable LLDP in NVM on port 0
Flash size is 6004736
EMP is 8034
EMPSettingsModuleHeaderOffsetW is 0001A000
LLDPConfigurationPtr is 0007
LLDPConfigurationOffset is 0001A00D
LLDPConfigurationLength is 0008
LLDPAdminStatusOffsetW is 0001A00E
Note: LLDPAdminWord is 3333
LLDPCRCOffset is 0001A015
LLDPCRC is 8038
Changed word 0001A00E to 0000
New CRC is A4
Changed word 0001A015 to 80A4
Writing modified flash of size 6004736...done.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After that we have it:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# lldpctl
-------------------------------------------------------------------------------
LLDP neighbors:
-------------------------------------------------------------------------------
Interface:    ens192, via: LLDP, RID: 1, Time: 0 day, 01:52:28
  Chassis:
    ChassisID:    mac 80:a2:35:21:a2:71
    ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h4 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h4&gt;

&lt;p&gt;This took me &lt;em&gt;four+&lt;/em&gt; hours to debug and read half the internet.&lt;/p&gt;
</description>
        <pubDate>Thu, 06 Jun 2019 00:00:00 +0000</pubDate>
        <link>https://donatas.net/blog/2019/06/06/vmware-esxi-lldp-i40ge/</link>
        <guid isPermaLink="true">https://donatas.net/blog/2019/06/06/vmware-esxi-lldp-i40ge/</guid>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>Git in operations</title>
        <description>&lt;p&gt;I was asked from developers to tell about git how we use it in operations team (aka SRE/DevOps). In an ideal world, developers should teach operation guys how to use git at scale. But sometimes reality is far away.&lt;/p&gt;

&lt;p&gt;Below are my short slides I prepared one hour before stand-up, keep it simple, stupid.&lt;/p&gt;

&lt;div style=&quot;left: 0; width: 100%; height: 0; position: relative; padding-bottom: 74.9288%;&quot;&gt;&lt;iframe src=&quot;//speakerdeck.com/player/4a0b12d46226415e9a4afb00b2f16add&quot; style=&quot;border: 0; top: 0; left: 0; width: 100%; height: 100%; position: absolute;&quot; allowfullscreen=&quot;&quot; scrolling=&quot;no&quot; allow=&quot;autoplay; encrypted-media&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;

&lt;p&gt;I will explain each command from the slides how I use it not only for work but for open-source contributions as well.&lt;/p&gt;

&lt;h3 id=&quot;git-config-list&quot;&gt;git config –list&lt;/h3&gt;

&lt;p&gt;List all the configurations per project or globally. I don’t think I use it at all, just for the setup phase maybe.&lt;/p&gt;

&lt;h3 id=&quot;git-config-global-pushdefault-current&quot;&gt;git config –global push.default current&lt;/h3&gt;

&lt;p&gt;This is very handy to avoid specifying the branch name you want to push. This allows you to use the current branch you are working right now by default.&lt;/p&gt;

&lt;h3 id=&quot;git-config-global-branchmasterremote-origin&quot;&gt;git config –global branch.master.remote origin&lt;/h3&gt;

&lt;p&gt;Usually, you have to type for instance &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git push origin master&lt;/code&gt;. Using this configuration knob and the previous one, you cut this command to just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git push&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The trick for Github users &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git config --global remote.origin.fetch +refs/pull/*/head:refs/remotes/pr/*&lt;/code&gt;. This command fetches the branches by pull request numbers. If a pull request has a number &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;123&lt;/code&gt;. Then you can check out locally to that branch by typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git checkout pr/123&lt;/code&gt;. Cool? Not? Continue reading.&lt;/p&gt;

&lt;h3 id=&quot;git-config-global-aliaslast-log--1-head&quot;&gt;git config –global alias.last ‘log -1 HEAD’&lt;/h3&gt;

&lt;p&gt;I always tend to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log -n 1&lt;/code&gt;. Using git aliases it could be more human readable like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git last&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;git-remote-add-upstream-https&quot;&gt;git remote add upstream https://&lt;/h3&gt;

&lt;p&gt;When you work on a local fork of an upstream repository where you don’t have write permissions you are out of sync of branches between your fork and the upstream. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git fetch --all&lt;/code&gt; helps you to have all branches an upstream has locally as well.&lt;/p&gt;

&lt;h3 id=&quot;git-log&quot;&gt;git log&lt;/h3&gt;

&lt;p&gt;Mostly I use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log&lt;/code&gt;, but if I want to find a relevant commit id by commit message I use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log --oneline | grep nginx&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log --grep &apos;nginx&apos;&lt;/code&gt;. If I need to find the commit by looking into the code, not only to commit message I use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log -S &apos;nginx&apos;&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;git-shortlog&quot;&gt;git shortlog&lt;/h3&gt;

&lt;p&gt;I rarely use this command. Mostly I use it when I want to see what are the most active contributors to the arbitrary project or it’s useful to have this information when publishing release notes.&lt;/p&gt;

&lt;p&gt;The output is well known for some people:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Donatas (2241):
      Merge pull request #1 from hostinger/feature/add_supermarket_cookbook
      Merge pull request #2 from hostinger/feature/add_hostinger-machine_cookbook
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git shortlog -s -n --all --no-merges&lt;/code&gt; gives us more statistic related view:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;% git shortlog -s -n --all --no-merges
  2685  Donatas Abraitis
   415  FirstName LastName
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;git-add&quot;&gt;git add&lt;/h3&gt;

&lt;p&gt;Every day I usually use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git add .&lt;/code&gt; to add all files recursively in a current directory, but sometimes I have to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git add &amp;lt;path&amp;gt;&lt;/code&gt; to add specific file or directory to skip some temporary files. I never used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git add --interactive&lt;/code&gt;. It’s quite fun but doesn’t look very handy at a first glance. It just slowdowns the process, IMHO.&lt;/p&gt;

&lt;p&gt;I use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git add --patch&lt;/code&gt; not often, but it’s useful if you changed more than one code places and finally, you need to add only a few of them (not all). Patch splits your changes into hunks and you are able to select which one to include.&lt;/p&gt;

&lt;p&gt;To remove the file you accidentally added you could do that by typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rm --cached &amp;lt;path&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;git-commit&quot;&gt;git commit&lt;/h3&gt;

&lt;p&gt;Sorry, all IDE &lt;em&gt;lovers&lt;/em&gt;, but &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git commit -m&lt;/code&gt; is really big crap. First of all, it teaches you to not think much about the commit message and description at all. Why? Because if you use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-m&lt;/code&gt; you probably want to push this commit as fast as possible without caring about the details. Lazy developers syndrome:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;* git add .
* git commit -m &apos;I do not care much about that&apos;
* git add .
* git commit -m &apos;I do not care much about that 2&apos;
* git add .
* git commit -m &apos;fix&apos;
* git push
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s talk about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git commit --signoff&lt;/code&gt;. Some big projects require you to sign before merging.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It is used to say that you certify that you have created the patch in question, or that you certify that to the best of your knowledge, it was created under an appropriate open-source license, or that it has been provided to you by someone else under those terms.&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;git-commit-amend&quot;&gt;git commit –amend&lt;/h3&gt;

&lt;p&gt;I always use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git commit --amend --allow-empty --signoff&lt;/code&gt; when committing. Amend is the feature which allows you to modify previous commit keeping the same commit message, description. It doesn’t create an additional commit, just appends the code you want. It’s required to have a single commit per pull request somewhere because some linters or CI/CD platforms run tests under commit and not under pull request. What happens when you have two commits where the later one fixes syntax while the formerly introduced syntax error. It would start two deployments per commit and both should fail.&lt;/p&gt;

&lt;h3 id=&quot;bad-commit-example&quot;&gt;bad commit example&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;commit a5140910088f33ec6edd3869a1354ebfafb63ff8
Author: joni2back &amp;lt;xxx@gmail.com&amp;gt;
Date:   Tue Mar 3 16:58:54 2015 -0300

    fix error
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What can you extract from this message? Absolutely absurd. Nothing. Oh, I can say that the author is doing his career well.&lt;/p&gt;

&lt;h3 id=&quot;good-commit-example&quot;&gt;good commit example&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;commit afad5cedf1be827238b376e63b0b93bb555c928e
Author: Donatas Abraitis &amp;lt;donatas.abraitis@gmail.com&amp;gt;
Date:   Mon Feb 25 21:16:02 2019 +0200

    bgpd: Add peer action for PEER_FLAG_IFPEER_V6ONLY flag

    peer_flag_modify() will always return BGP_ERR_INVALID_FLAG because
    the action was not defined for PEER_FLAG_IFPEER_V6ONLY flag.

    ```
    global PEER_FLAG_IFPEER_V6ONLY = 16384;
    global BGP_ERR_INVALID_FLAG = -2;

    probe process(&quot;/usr/lib/frr/bgpd&quot;).statement(&quot;peer_flag_modify@/root/frr/bgpd/bgpd.c:3975&quot;)
    {
        if ($flag == PEER_FLAG_IFPEER_V6ONLY &amp;amp;&amp;amp; $action-&amp;gt;type == 0)
                printf(&quot;action not found for the flag PEER_FLAG_IFPEER_V6ONLY\n&quot;);
    }

    probe process(&quot;/usr/lib/frr/bgpd&quot;).function(&quot;peer_flag_modify&quot;).return
    {
        if ($return == BGP_ERR_INVALID_FLAG)
                printf(&quot;return BGP_ERR_INVALID_FLAG\n&quot;);
    }
    ```
    produces:
    action not found for the flag PEER_FLAG_IFPEER_V6ONLY
    return BGP_ERR_INVALID_FLAG

    $ vtysh -c &apos;conf t&apos; -c &apos;router bgp 20&apos; -c &apos;neighbor eth1 interface v6only remote-as external&apos;

    Signed-off-by: Donatas Abraitis &amp;lt;donatas.abraitis@gmail.com&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A bit better example of how good commit message should look like. I don’t say it’s ideal, but it’s good enough to understand what’s going on.&lt;/p&gt;

&lt;h3 id=&quot;git-rebase&quot;&gt;git rebase&lt;/h3&gt;

&lt;p&gt;Most of the time I use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase --interactive master&lt;/code&gt;. But if an arbitrary project has release branches I use for instance &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase --interactive stable/7.0&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;git-stash&quot;&gt;git stash&lt;/h3&gt;

&lt;p&gt;I don’t use stash often, but it’s a cool feature git provides. It’s like a buffer or storage where you put your changes without committing and can jump between branches. Let’s say I work on a feature branch and I need to switch to the master branch to pull new changes. Not possible if I have some changes already. I need to stash my changes to the buffer and retrieve those changes later using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git stash pop&lt;/code&gt; or restore back to more accurate revision. You can list all stashes with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git stash list&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;git-reset&quot;&gt;git reset&lt;/h3&gt;

&lt;p&gt;Let’s say I committed a bad commit or amended to the previous commit without creating a commit before (overwritten someone’s changes). In such cases I use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log -n 2&lt;/code&gt; to grab the commit id I want to reset to. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git commit &amp;lt;sha1&amp;gt;&lt;/code&gt;. Then I’m able to commit my changes again.&lt;/p&gt;

&lt;p&gt;Git allows you to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--hard&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--soft&lt;/code&gt; method for reset action. With soft you lose only the commit history. With hard, you lose the changes as well.&lt;/p&gt;

&lt;h3 id=&quot;git-tag&quot;&gt;git tag&lt;/h3&gt;

&lt;p&gt;I’m not a fan of using tags. But some projects use them. Basically, there are two types of tags: annotated and lightweight. The latter one just marks the commit with arbitrary tag while the former one creates some metadata in the history, like data, author, message.&lt;/p&gt;

&lt;h3 id=&quot;git-bisect&quot;&gt;git bisect&lt;/h3&gt;

&lt;p&gt;I discovered this feature a few months ago. It’s very cool. Want to find the commit which broke functionality or which caused regression? Bisect can help you. You specify a good and a bad commits before the start:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git bisect start
git bisect bad &amp;lt;sha1&amp;gt;
git bisect good &amp;lt;sha1&amp;gt;
git bisect bad
...
git bisect reset
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or you can automate this by using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git bisec run &amp;lt;cmd&amp;gt;&lt;/code&gt;. Where &lt;em&gt;cmd&lt;/em&gt; is the script which handles bad/good commits by exit code.&lt;/p&gt;

&lt;h3 id=&quot;git-cherry-pick&quot;&gt;git cherry-pick&lt;/h3&gt;

&lt;p&gt;What if I want to pick the commit which is already on the master and &lt;em&gt;recommit&lt;/em&gt; it to another branch, let’s say &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stable/7.0&lt;/code&gt;? Create one more commit or pick the same commit which is on the master branch and backport it to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stable/7.0&lt;/code&gt;? &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git cherry-pick &amp;lt;sha1&amp;gt;&lt;/code&gt; does the trick.&lt;/p&gt;

&lt;h3 id=&quot;git-reflog&quot;&gt;git reflog&lt;/h3&gt;

&lt;p&gt;I used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reflog&lt;/code&gt; I think fewer times than I have fingers on my hands. But it’s a really tough feature. For instance, if I used to amend and broke my commit, I’m able to recover to the previous state of the same commit by &lt;em&gt;traveling in time&lt;/em&gt; ;-) It’s like a git time machine.&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;I don’t realize my daily work without git. It’s a critical tool for day to day work even in operations. Truly stupid, but even lawyers nowadays are  using Github to publish chapters publicly.&lt;/p&gt;

&lt;p&gt;When you code for work, you mostly do not need git command such as git bisect or git cherry pick and so on. That’s why I’m always looking for open-source contributions - to learn something new again and again.&lt;/p&gt;

&lt;p&gt;Keep commits as small as possible to help to bisect truly relevant commit instead of reviewing elephant one.&lt;/p&gt;
</description>
        <pubDate>Wed, 01 May 2019 00:00:00 +0000</pubDate>
        <link>https://donatas.net/blog/2019/05/01/git-in-operations/</link>
        <guid isPermaLink="true">https://donatas.net/blog/2019/05/01/git-in-operations/</guid>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>Got my own IPv6 address 2019::E</title>
        <description>&lt;h4 id=&quot;preparation&quot;&gt;Preparation&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.cumulusnetworks.com/&quot;&gt;Official documentation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://education.cumulusnetworks.com/series/linux-fundamentals&quot;&gt;Linux networking fundamentals&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://education.cumulusnetworks.com/series/cumulus-core&quot;&gt;Cumulus Core course&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://cumulusnetworks.com/support/networking-training/&quot;&gt;Boot camp&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Working experience big plus&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;experience-required&quot;&gt;Experience required?&lt;/h4&gt;

&lt;p&gt;After passing the exam I could say that the list of materials above is not quite enough to prepare because some questions I just knew from my last experience with Cisco certifications.&lt;/p&gt;

&lt;h4 id=&quot;how-long-it-takes-to-prepare&quot;&gt;How long it takes to prepare?&lt;/h4&gt;

&lt;p&gt;I took one week vacation and read as much as I can, played with virtual environments, attended boot camp.&lt;/p&gt;

&lt;h4 id=&quot;testing-environment&quot;&gt;Testing environment&lt;/h4&gt;

&lt;p&gt;This is the most interesting piece.&lt;/p&gt;

&lt;p&gt;First of all, Cumulus decided to work with &lt;a href=&quot;https://proctoru.com&quot;&gt;Proctoru.com&lt;/a&gt; for certifications. Ok, I went to &lt;a href=&quot;https://test-it-out.proctoru.com/&quot;&gt;test&lt;/a&gt; if my Linux workstation is able to deal with Proctoru requirements.&lt;/p&gt;

&lt;p&gt;Unfortunately, Linux is not supported by Proctoru.&lt;/p&gt;

&lt;p&gt;I decided to use &lt;a href=&quot;https://www.virtualbox.org/&quot;&gt;VirtualBox&lt;/a&gt; with Windows 7 as a guest. Shared my webcam, microphone, etc. The test was green.
I fully trusted that it’s done and I can easily wait for an exam date.&lt;/p&gt;

&lt;p&gt;Exam date came. I filled all the necessary data like passport details, pictures, etc. But in the last stage, I got an error that please disable “VirtualBox integrated camera”. Wait. What?&lt;/p&gt;

&lt;p&gt;Contacted support. They said that’s not allowed to use VirtualBox at all. Well done Proctoru.com, well done.&lt;/p&gt;

&lt;p&gt;I called my co-worker to ask if he could borrow a laptop with OSX. Ok, I got my new laptop which is fully supported now.&lt;/p&gt;

&lt;p&gt;I’m sitting in our meeting room alone. Supervisor asked me to show the room around, put the phone in front of my laptop. That’s fine. Later on, she said that this place is not private and not allowed by the institution. Damn it, I had to move to another place.&lt;/p&gt;

&lt;p&gt;I rushed to our other office where actually we have &lt;a href=&quot;https://i.pinimg.com/736x/4c/f8/e7/4cf8e70a61a836eab48926c1cbb264cb--coworking-space-wing-chairs.jpg&quot;&gt;silent boxes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Again, did the same procedure and eventually, another supervisor said - it’s not a private place. What the hell is this? I asked where should I go? Can I take an exam inside the car? She said - yes because the car is a private space. No problem, I ran to my car, did the same procedures.&lt;/p&gt;

&lt;p&gt;Surprise surprise? Wonder what she said to me? This is NOT a private space, move to private space! I won’t say what I said to them (angry). I asked to figure out and look at chat history because the previous supervisor told me to move to the car. It was misunderstanding from their point of view. I rescheduled the exam already the third time.&lt;/p&gt;

&lt;p&gt;I decided to go to my home where I don’t live there yet (under construction). This is the private space according to them. Ok, sweaty, warm and angry I started my exam adventure.&lt;/p&gt;

&lt;h4 id=&quot;difficulty&quot;&gt;Difficulty&lt;/h4&gt;

&lt;p&gt;One guy from Cumulus said that the exam is really not so easy, but I took the risks and tried to pass it immediately without learning more around.&lt;/p&gt;

&lt;p&gt;For me personally, it wasn’t hard. I would say due to my past and current networking experience.&lt;/p&gt;

&lt;p&gt;The most difficult part was that I was quite stressed due to the truly stupid examination process.&lt;/p&gt;

&lt;h4 id=&quot;compare-with-ccnp&quot;&gt;Compare with CCNP?&lt;/h4&gt;

&lt;p&gt;Comparing with Cisco exams, especially with CCNP this looks harder because you have to know more, not only command line commands and theory. CCNOP includes command line, theory, Linux and automation chapters.&lt;/p&gt;

&lt;p&gt;Another advantage while the exam’s program is young is that there are no braindumps to peck and go. I’m sure there will someone leak questions for this exam as well. That’s why I decided to pass it before instead of cheating.&lt;/p&gt;

&lt;h4 id=&quot;was-it-worth&quot;&gt;Was it worth?&lt;/h4&gt;

&lt;p&gt;I think it was worth. I’m not going to continue with Cisco certification anymore because white-box networking is the future. Even better, you can always spot the problem and try to figure out it yourself instead of just filling an issue. And for extra Brownie points maybe contribute to upstream?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/ccnop.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
</description>
        <pubDate>Sun, 10 Mar 2019 00:00:00 +0000</pubDate>
        <link>https://donatas.net/blog/2019/03/10/cumulus-certified-open-networking-professional/</link>
        <guid isPermaLink="true">https://donatas.net/blog/2019/03/10/cumulus-certified-open-networking-professional/</guid>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>Prevent route leaks by explicitly defining policy</title>
        <description>&lt;p&gt;Route leaks or even hijacks are one of the biggest flaws in global routing.&lt;/p&gt;

&lt;p&gt;What are the route leaks? Literally, there are prefixes announced accidentally due to wrongly configured import/export filters. Or those filters do not exist at all.&lt;/p&gt;

&lt;p&gt;If a customer or a peer sends routes outside his scope and a provider accepts them, we call those events as route leaks.&lt;/p&gt;

&lt;p&gt;Route leaks are more referred to accidentally events, while hijacks are an illegitimate takeover of IP addresses by corrupting routing tables. In such a case, scammers can route the traffic as he wishes. To avoid the aforementioned events providers MUST take care of strict filters what to accept from peers and customers.&lt;/p&gt;

&lt;p&gt;Most known filters are:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt; &lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Easy to implement&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Major vendors support&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Pros&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Cons&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;RPKI&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;X&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Accept valid prefixes from peers and customers. No need to define any prefix-lists and other ACLs.&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Requires external validators.  Takes more time for peers to implement.  Not much precise at the moment because peers do not update ROA records properly.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;prefix-list&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;X&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;X&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Accepts only defined ranges of prefixes. Allows specifying a dynamic prefix mask (ge, le).&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Can’t filter out prefixes by AS-PATH.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;distribute-list&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;X&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;X&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Same as prefix-list, but less mature.&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Can’t filter out prefixes by AS-PATH.  Cannot assign dynamic prefix mask as prefix-list does.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;as-path access-lists&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;X&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;X&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Filter routes by AS-PATH only.&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Cannot filter routes by prefixes.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;maximum-prefix&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;X&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;X&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Set maximum prefix number for a peer or a customer to avoid overfilling the Adj-RIBs-In.&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;This is too much aggressive if one side decides to restart the session under some circumstances.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;WHOIS database filtering&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Accept prefixes only defined in WHOIS database (RIPE, APNIC, etc.). This is more accurate at the moment comparing with RPKI.&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Takes more time to converge. Changes are visible typically in 24 hours. Requires external services to update the control plane.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;RFC8212&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;X&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Accept and/or announce prefixes only if one of the aforementioned filtering techniques applied.  This is bidirectional forwarding due to filtering both directions.&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Only FRRouting at the moment supports this RFC.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Another interesting approach I found is by implementing roles where each neighbor defines the role: customer, peer, internal, provider. This approach appends &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BGP Open message&lt;/code&gt; to establish an agreement of the relationship of two neighbors. Propagated routes are then marked with iOTC (The Internal Only To Customer)] attribute according to agreed relationship allowing prevention of route leaks.&lt;/p&gt;

&lt;p&gt;More about that you can read on &lt;a href=&quot;https://tools.ietf.org/html/draft-ietf-idr-bgp-open-policy-02&quot;&gt;htt ps://tools.ietf.org/html/draft-ietf-idr-bgp-open-policy-02&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We discussed this draft in short in the FRRouting group, but at the moment there is nothing to implement while it’s not released as RFC. And this draft
is questionable if it would give any reasonable effect right now. It would take a huge amount of time to implement for both sides. It’s absolutely fine if you use only &lt;a href=&quot;https://frrouting.org/&quot;&gt;FRRouting daemons&lt;/a&gt;, but what about a vendor-agnostic solution?&lt;/p&gt;

&lt;p&gt;Instead of using roles in updates and open messages, I found &lt;a href=&quot;https://tools.ietf.org/html/rfc8212&quot;&gt;https://tools.ietf.org/html/rfc8212&lt;/a&gt; which sounds reasonable to implement.&lt;/p&gt;

&lt;p&gt;The RFC defines that both peering sides should require import/exporter filters explicitly defined. What does it mean? By default, all(?) vendors do not require route-map to be configured for a neighbor.&lt;/p&gt;

&lt;p&gt;The snippet below will announce everything it has in its &lt;em&gt;Adj-RIB-Out&lt;/em&gt; for neighbor 192.168.3.1.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;router bgp 65031
 neighbor 192.168.3.1 remote-as 65032
 !
 address-family ipv4 unicast
  redistribute connected
 exit-address-family
!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/FRRouting/frr/pull/3746&quot;&gt;Here&lt;/a&gt; we have a new BGP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bgp ebgp-requires-policy&lt;/code&gt; knob which requires filters (filter-list, distribute-list, prefix-list or route-map defined) for every eBGP session.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/rfc8212.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;router bgp 65031
 bgp ebgp-requires-policy
 neighbor 192.168.3.1 remote-as 65032
 !
 address-family ipv4 unicast
  redistribute connected
  neighbor 192.168.3.1 prefix-list exit4-in in
  neighbor 192.168.3.1 route-map exit4-out out
 exit-address-family
!
ip prefix-list exit4-in permit 10.0.0.0/24
!
route-map exit4-out permit 10
!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To clarify, if we remove inbound prefix-list from this neighbor, we will receive zero prefixes due to default behavior.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;router bgp 65031
 bgp ebgp-requires-policy
 neighbor 192.168.3.1 remote-as 65032
 !
 address-family ipv4 unicast
  redistribute connected
  neighbor 192.168.3.1 route-map exit4-out out
 exit-address-family
!
route-map exit4-out permit 10
!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Adj-RIB-In table for neighbor 192.168.3.1 will be equal to zero prefixes. It prevents accepting any prefixes if the policy is forgotten to define explicitly.&lt;/p&gt;

&lt;p&gt;Even though we see an informational warning that &lt;em&gt;Inbound updates discarded due to missing policy&lt;/em&gt; under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;show bgp neighbors 192.168.3.1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hence, instead of just reading the documentation, it’s more fun to play archeologist and try to implement this into real-life examples. An attempt to cool again.&lt;/p&gt;
</description>
        <pubDate>Tue, 19 Feb 2019 00:00:00 +0000</pubDate>
        <link>https://donatas.net/blog/2019/02/19/ebgp-requires-policy/</link>
        <guid isPermaLink="true">https://donatas.net/blog/2019/02/19/ebgp-requires-policy/</guid>
        
        
        <category>blog</category>
        
      </item>
    
      <item>
        <title>Traffic steering using GeoDNS and IPv6</title>
        <description>&lt;p&gt;Using DNS-based load balancing doesn’t save you from the failure. DNS server doesn’t know if the backend is up or down. It just responds without carrying about the state of the backend.&lt;/p&gt;

&lt;p&gt;So if you have two or more IPs per record, DNS server will respond in a round-robin manner. Let’s say one backend of two is under maintenance (down) and another is alive. Eventually, all connections affected by first backend failures will be re-established to another instance (if TTL is small enough, e.g.: 30 seconds).&lt;/p&gt;

&lt;p&gt;Typically TTL is set to one hour or so. Some resolvers override source TTL to cache DNS responses longer. If you use DNS as a balancing layer then small TTL must be used, like 30 seconds.&lt;/p&gt;

&lt;p&gt;This could be improved by using &lt;a href=&quot;https://donatas.net/blog/2017/03/01/powerdns-pipebackend/&quot;&gt;circuit breaker&lt;/a&gt; between the server and the client.&lt;/p&gt;

&lt;p&gt;A further step to achieve more granular stickiness would be to use GeoDNS service e.g.: PowerDNS. It has full support for &lt;a href=&quot;https://dev.maxmind.com/geoip/legacy/downloadable/&quot;&gt;MaxMind legacy GeoIP&lt;/a&gt; and &lt;a href=&quot;https://dev.maxmind.com/geoip/geoip2/downloadable/&quot;&gt;GeoIP2&lt;/a&gt;. It could return address by country, city, continent. Just keep in mind that GeoIP &lt;em&gt;dat&lt;/em&gt; format is not maintained anymore. Consider using &lt;em&gt;mmdb&lt;/em&gt; format. PowerDNS looks up what to return by source IP of the resolver or EDNS - if forwarded.&lt;/p&gt;

&lt;p&gt;If your DNS server is dual-stacked, make sure you use both families of GeoIP data (IPv4 and IPv6). Otherwise, it will respond with surprising results.&lt;/p&gt;

&lt;p&gt;You could even craft your own mapping conditions on how to respond to arbitrary queries. Like Facebook has offline DNS map cartographer service. The simplest way is to write in CVS and export to dat/mmdb.&lt;/p&gt;

&lt;p&gt;But again this does not guaranty high availability if the backend is down.&lt;/p&gt;

&lt;p&gt;Here come CDN providers. Put your website under CDN, cache as much as possible masking backend failures. Some CDN providers have their own load balancers thus you should not care much about how they route the traffic to your website. Again, that’s not free from failures.&lt;/p&gt;

&lt;p&gt;Instead of using CDN load balancer, implement anycast over more locations to spread the traffic to the nearest location. Sometimes one is better than many. I refer one as a single anycast address which is deployed between a few locations.&lt;/p&gt;

&lt;p&gt;I must mention that $anycast is expensive to deploy because maintenance and monitoring are hard. In addition, anycast is not always end-user friendly because of not very fair routing. Sometimes even de-tour occurs in the path from the source to destination.&lt;/p&gt;

&lt;p&gt;You should allocate the whole &lt;em&gt;/24&lt;/em&gt; block for it (yeah, this is the smallest prefix length over global BGP table). So if you are planning to use only a few addresses from the whole /24 block - that’s not the way to go.&lt;/p&gt;

&lt;p&gt;If you have only a few locations then no point to use anycast globally. Too much headache.&lt;/p&gt;

&lt;p&gt;Even though you have quite enough PoPs, you must ensure your whois information is up-to-date because some ISPs generates route maps according to &lt;em&gt;inetnum&lt;/em&gt; country field. Hence a lot of monitoring and traffic engineering stuff are involved.&lt;/p&gt;

&lt;p&gt;One more interesting approach is using CDN in front and anycast at the backends. In this case, CDN provider will load balance your traffic using anycast address, but again you are not sure if your content is served from the right region.
To improve this setup we can install GeoDNS server and ask CDN’s resolver to query CNAME record instead of A/AAAA. GeoDNS, in turn, will respond with appropriate backend’s address according to resolver’s (or EDNS) source IP.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;As I mentioned above IPv4 anycast is an expensive solution, but not for an old good friend - IPv6!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this blog post, I would like to explain sophisticated (not for networking guys) approach on how to handle failovers gracefully. With IPv6 things change. As drawn in the diagram you should see that every PoP has two prefixes announced.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/ipv6-geodns-failover.png&quot; alt=&quot;ipv6-geodns-failover&quot; /&gt;&lt;/p&gt;

&lt;p&gt;One global anycast plus region allocated prefix. Both are overlapping prefixes which allow having smooth failover if one region goes down completely. For instance, your GeoDNS server responds to CNAME record with IP &lt;em&gt;2A02:4780:C3::1&lt;/em&gt; for the CDN’s resolver and at that moment this region is down. New connections will be redirected to the shortest AS-PATH PoP because of global anycast overlapped network.&lt;/p&gt;

&lt;p&gt;You should deploy this setup if you care about the infrastructure - it allows you to turn off the whole PoP (or DC) for testing (or Chaos engineering) purposes. Everything you are not testing is breaking.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Chaos engineering will allow you to personally meet all of your colleagues within a short time – whether you want to or not!&lt;/p&gt;
&lt;/blockquote&gt;
</description>
        <pubDate>Fri, 14 Dec 2018 00:00:00 +0000</pubDate>
        <link>https://donatas.net/blog/2018/12/14/geodns-ipv6-failover/</link>
        <guid isPermaLink="true">https://donatas.net/blog/2018/12/14/geodns-ipv6-failover/</guid>
        
        
        <category>blog</category>
        
      </item>
    
  </channel>
</rss>
