docs: update home-gateway use-case
[vpp.git] / docs / usecases / home_gateway.rst
1 VPP as a Home Gateway
2 =====================
3
4 Vpp running on a small system (with appropriate NICs) makes a fine home
5 gateway. The resulting system performs far in excess of requirements: a
6 debug image runs at a vector size of ~1.2 terminating a 150-mbit down /
7 10-mbit up cable modem connection.
8
9 At a minimum, install sshd and the isc-dhcp-server. If you prefer, you
10 can use dnsmasq.
11
12 System configuration files
13 --------------------------
14
15 /etc/vpp/startup.conf:
16
17 .. code-block:: c
18
19    unix {
20      nodaemon
21      log /var/log/vpp/vpp.log
22      full-coredump
23      cli-listen /run/vpp/cli.sock
24      startup-config /setup.gate
25      poll-sleep-usec 100
26      gid vpp
27    }
28    api-segment {
29      gid vpp
30    }
31    dpdk {
32         dev 0000:03:00.0
33         dev 0000:14:00.0
34         etc.
35     }
36
37     plugins {
38       ## Disable all plugins, selectively enable specific plugins
39           ## YMMV, you may wish to enable other plugins (acl, etc.)
40       plugin default { disable }
41       plugin dhcp_plugin.so { enable }
42       plugin dns_plugin.so { enable }
43       plugin dpdk_plugin.so { enable }
44       plugin nat_plugin.so { enable }
45       plugin ping_plugin.so { enable }
46           ## if you plan to use the time-based MAC filter
47       plugin mactime_plugin.so { enable }
48       plugin vmxnet3_plugin.so { enable }
49     }
50
51 /etc/dhcp/dhcpd.conf:
52
53 .. code-block:: c
54
55    subnet 192.168.1.0 netmask 255.255.255.0 {
56      range 192.168.1.10 192.168.1.99;
57      option routers 192.168.1.1;
58      option domain-name-servers 8.8.8.8;
59    }
60
61 If you decide to enable the vpp dns name resolver, substitute
62 192.168.1.2 for 8.8.8.8 in the dhcp server configuration.
63
64 /etc/default/isc-dhcp-server:
65
66 .. code-block:: c
67
68    # On which interfaces should the DHCP server (dhcpd) serve DHCP requests?
69    # Separate multiple interfaces with spaces, e.g. "eth0 eth1".
70    INTERFACESv4="lstack"
71    INTERFACESv6=""
72
73 /etc/ssh/sshd_config:
74
75 .. code-block:: c
76
77    # What ports, IPs and protocols we listen for
78    Port <REDACTED-high-number-port>
79    # Change to no to disable tunnelled clear text passwords
80    PasswordAuthentication no
81
82 For your own comfort and safety, do NOT allow password authentication
83 and do not answer ssh requests on port 22. Experience shows several
84 hack attempts per hour on port 22, but none on random high-number
85 ports.
86
87 Systemd configuration
88 ---------------------
89
90 In a typical home-gateway use-case, vpp owns the one-and-only WAN link
91 with a prayer of reaching the public internet. Simple things like
92 updating distro software requires use of the "lstack" interface created
93 above, and configuring a plausible upstream DNS name resolver.
94
95 Configure /etc/systemd/resolved.conf as follows.
96
97 /etc/systemd/resolved.conf:
98
99 .. code-block:: c
100
101    [Resolve]
102    DNS=8.8.8.8
103    #FallbackDNS=
104    #Domains=
105    #LLMNR=no
106    #MulticastDNS=no
107    #DNSSEC=no
108    #Cache=yes
109    #DNSStubListener=yes
110
111 Netplan configuration
112 ---------------------
113
114 If you want to configure a static IP address on one of your home-gateway
115 Ethernet ports on Ubuntu 18.04, you'll need to configure netplan.
116 Netplan is relatively new. It and the network manager GUI and can be
117 cranky. In the configuration shown below, s/enp4s0/<your-interface>/...
118
119 /etc/netplan-01-netcfg.yaml:
120
121 .. code-block:: c
122
123    # This file describes the network interfaces available on your system
124    # For more information, see netplan(5).
125    network:
126      version: 2
127      renderer: networkd
128      ethernets:
129        enp4s0:
130          dhcp4: no
131          addresses: [192.168.2.254/24]
132          gateway4: 192.168.2.100
133          nameservers:
134            search: [my.local]
135            addresses: [8.8.8.8]
136
137 /etc/systemd/network-10.enp4s0.network:
138
139 .. code-block:: c
140
141    [Match]
142    Name=enp4s0
143
144    [Link]
145    RequiredForOnline=no
146
147    [Network]
148    ConfigureWithoutCarrier=true
149    Address=192.168.2.254/24
150
151 Note that we've picked an IP address for the home gateway which is on an
152 independent unrouteable subnet. This is handy for installing (and
153 possibly reverting) new vpp software.
154
155 VPP Configuration Files
156 -----------------------
157
158 Here we see a nice use-case for the vpp debug CLI macro expander:
159
160 /setup.gate:
161
162 .. code-block:: c
163
164    define HOSTNAME vpp1
165    define TRUNK GigabitEthernet3/0/0
166
167    comment { Specific MAC address yields a constant IP address }
168    define TRUNK_MACADDR 48:f8:b3:00:01:01
169    define BVI_MACADDR 48:f8:b3:01:01:02
170
171    comment { inside subnet 192.168.<inside_subnet>.0/24 }
172    define INSIDE_SUBNET 1
173
174    # Adjust as needed to match PCI addresses of inside network ports
175    define INSIDE_PORT1 GigabitEthernet6/0/0
176    define INSIDE_PORT2 GigabitEthernet6/0/1
177    define INSIDE_PORT3 GigabitEthernet8/0/0
178    define INSIDE_PORT4 GigabitEthernet8/0/1
179
180    comment { feature selections }
181    define FEATURE_ADL uncomment
182    define FEATURE_NAT44 uncomment
183    define FEATURE_CNAT comment
184    define FEATURE_DNS comment
185    define FEATURE_IP6 comment
186    define FEATURE_IKE_RESPONDER comment
187    define FEATURE_MACTIME uncomment
188    define FEATURE_OVPN uncomment
189    define FEATURE_MODEM_ROUTE uncomment
190
191    exec /setup.tmpl
192
193 /setup.tmpl:
194
195 .. code-block:: c
196
197    show macro
198
199    set int mac address $(TRUNK) $(TRUNK_MACADDR)
200    set dhcp client intfc $(TRUNK) hostname $(HOSTNAME)
201    set int state $(TRUNK) up
202
203    bvi create instance 0
204    set int mac address bvi0 $(BVI_MACADDR)
205    set int l2 bridge bvi0 1 bvi
206    set int ip address bvi0 192.168.$(INSIDE_SUBNET).1/24
207    set int state bvi0 up
208
209    set int l2 bridge $(INSIDE_PORT1) 1
210    set int state $(INSIDE_PORT1) up
211    set int l2 bridge $(INSIDE_PORT2) 1
212    set int state $(INSIDE_PORT2) up
213    set int l2 bridge $(INSIDE_PORT3) 1
214    set int state $(INSIDE_PORT3) up
215    set int l2 bridge $(INSIDE_PORT4) 1
216    set int state $(INSIDE_PORT4) up
217
218    comment { dhcp server and host-stack access }
219    create tap host-if-name lstack host-ip4-addr 192.168.$(INSIDE_SUBNET).2/24 host-ip4-gw 192.168.$(INSIDE_SUBNET).1
220    set int l2 bridge tap0 1
221    set int state tap0 up
222
223    service restart isc-dhcp-server
224
225    $(FEATURE_ADL) { bin adl_interface_enable_disable $(TRUNK) }
226    $(FEATURE_ADL) { ip table 1 }
227    $(FEATURE_ADL) { ip route add table 1 0.0.0.0/0 via local }
228
229    $(FEATURE_NAT44) { nat44 forwarding enable }
230    $(FEATURE_NAT44) { nat44 plugin enable sessions 63000 }
231    $(FEATURE_NAT44) { nat44 add interface address $(TRUNK) }
232    $(FEATURE_NAT44) { set interface nat44 in bvi0 out $(TRUNK) }
233
234    $(FEATURE_NAT44) { nat44 add static mapping local 192.168.$(INSIDE_SUBNET).2 22342 external $(TRUNK) 22342 tcp }
235    $(FEATURE_NAT44) { $(FEATURE_IKE_RESPONDER) { nat44 add identity mapping external $(TRUNK) udp 500 } }
236    $(FEATURE_NAT44) { $(FEATURE_IKE_RESPONDER) { nat44 add identity mapping external $(TRUNK) udp 4500 } }
237    $(FEATURE_NAT44) { $(FEATURE_DNS) { nat44 add static mapping local 192.168.$(INSIDE_SUBNET).2 53053 external $(TRUNK) 53053 udp } }
238    $(FEATURE_NAT44) { $(FEATURE_OVPN) { nat44 add static mapping local 192.168.$(INSIDE_SUBNET).2 37979 external $(TRUNK) 37979 udp } }
239    $(FEATURE_NAT44) { $(FEATURE_OVPN) { set interface feature bvi0 skipnat arc ip4-unicast } }
240    $(FEATURE_NAT44) { $(FEATURE_OVPN) { ip route add 192.168.10.0/24 via 192.168.$(INSIDE_SUBNET).2 } }
241
242    $(FEATURE_CNAT) { set cnat snat-policy none }
243    $(FEATURE_CNAT) { set cnat snat-policy addr $(TRUNK) }
244    $(FEATURE_CNAT) { set interface feature bvi0 cnat-snat-ip4 arc ip4-unicast }
245    $(FEATURE_CNAT) { cnat translation add proto tcp real $(TRUNK) 22342 to -> 192.168.$(INSIDE_SUBNET).2 22342 }
246    $(FEATURE_CNAT) { $(FEATURE_DNS) { cnat translation add proto udp real $(TRUNK) 53053 to -> 192.168.$(INSIDE_SUBNET).1 53053 } }
247    $(FEATURE_CNAT) { $(FEATURE_OVPN) { cnat translation add proto udp real $(TRUNK) 37979 to -> 192.168.$(INSIDE_SUBNET).2 37979 } }
248    $(FEATURE_CNAT) { $(FEATURE_OVPN) { set interface feature bvi0 skipnat arc ip4-unicast } }
249    $(FEATURE_CNAT) { $(FEATURE_OVPN) { ip route add 192.168.10.0/24 via 192.168.$(INSIDE_SUBNET).2 } }
250
251
252    $(FEATURE_DNS) { nat44 add identity mapping external $(TRUNK) udp 53053 }
253    $(FEATURE_DNS) { bin dns_name_server_add_del 8.8.8.8 }
254    $(FEATURE_DNS) { bin dns_enable_disable }
255
256    $(FEATURE_IP6) { set int ip6 table $(TRUNK) 0 }
257    $(FEATURE_IP6) { ip6 nd address autoconfig $(TRUNK) default-route }
258    $(FEATURE_IP6) { dhcp6 client $(TRUNK) }
259    $(FEATURE_IP6) { dhcp6 pd client $(TRUNK) prefix group hgw }
260    $(FEATURE_IP6) { set ip6 address bvi0 prefix group hgw ::1/64 }
261    $(FEATURE_IP6) { ip6 nd address autoconfig bvi0 default-route }
262    comment { iPhones seem to need lots of RA messages... }
263    $(FEATURE_IP6) { ip6 nd bvi0 ra-managed-config-flag ra-other-config-flag ra-interval 30 20 ra-lifetime 180 }
264    comment { ip6 nd bvi0 prefix 0::0/0  ra-lifetime 100000 }
265
266    comment { responder profile }
267    $(FEATURE_IKE_RESPONDER) { ikev2 profile add swan }
268    $(FEATURE_IKE_RESPONDER) { ikev2 profile set swan auth rsa-sig cert-file /home/dbarach/certs/swancert.pem }
269    $(FEATURE_IKE_RESPONDER) { set ikev2 local key /home/dbarach/certs/dorakey.pem }
270    $(FEATURE_IKE_RESPONDER) { ikev2 profile set swan id remote fqdn swan.barachs.net }
271    $(FEATURE_IKE_RESPONDER) { ikev2 profile set swan id local fqdn broiler2.barachs.net }
272    $(FEATURE_IKE_RESPONDER) { ikev2 profile set swan traffic-selector remote ip-range 192.168.1.0 - 192.168.1.255 port-range 0 - 65535 protocol 0 }
273    $(FEATURE_IKE_RESPONDER) { ikev2 profile set swan traffic-selector local ip-range 192.168.$(INSIDE_SUBNET).0 - 192.168.$(INSIDE_SUBNET).255 port-range 0 - 65535 protocol 0 }
274    $(FEATURE_IKE_RESPONDER) { create ipip tunnel src 73.120.164.15 dst 162.255.170.167 }
275    $(FEATURE_IKE_RESPONDER) { ikev2 profile set swan tunnel ipip0 }
276
277    $(FEATURE_IKE_RESPONDER) { set int mtu packet 1390 ipip0 }
278    $(FEATURE_IKE_RESPONDER) { set int unnum ipip0 use $(TRUNK) }
279
280    comment { if using the mactime plugin, configure it }
281    $(FEATURE_MACTIME) { bin mactime_add_del_range name roku mac 00:00:01:de:ad:be allow-static }
282    $(FEATURE_MACTIME) { bin mactime_enable_disable $(INSIDE_PORT1) }
283    $(FEATURE_MACTIME) { bin mactime_enable_disable $(INSIDE_PORT2) }
284    $(FEATURE_MACTIME) { bin mactime_enable_disable $(INSIDE_PORT3) }
285    $(FEATURE_MACTIME) { bin mactime_enable_disable $(INSIDE_PORT4) }
286
287    $(FEATURE_MODEM_ROUTE) { ip route add 192.168.100.1/32 via $(TRUNK) }
288
289 Installing new vpp software
290 ---------------------------
291
292 If you're **sure** that a given set of vpp Debian packages will install
293 and work properly, you can install them while logged into the gateway
294 via the lstack / nat path. This procedure is a bit like standing on a
295 rug and yanking it. If all goes well, a perfect back-flip occurs. If
296 not, you may wish that you'd configured a static IP address on a
297 reserved Ethernet interface as described above.
298
299 Installing a new vpp image via ssh to 192.168.1.2:
300
301 .. code-block:: c
302
303    # nohup dpkg -i *.deb >/dev/null 2>&1 &
304
305 Within a few seconds, the inbound ssh connection SHOULD begin to respond
306 again. If it does not, you'll have to debug the issue(s).
307
308 Reasonably Robust Remote Software Installation
309 ----------------------------------------------
310
311 Here are a couple of scripts which yield a reasonably robust software
312 installation scheme.
313
314 Build-host script
315 ~~~~~~~~~~~~~~~~~
316
317 .. code-block:: c
318
319    #!/bin/bash
320
321    buildroot=/scratch/vpp-workspace/build-root
322    if [ $1x = "testx" ] ; then
323        subdir="test"
324        ipaddr="192.168.2.48"
325    elif [ $1x = "foox" ] ; then
326        subdir="foo"
327        ipaddr="foo.some.net"
328    elif [ $1x = "barx" ] ; then
329        subdir="bar"
330        ipaddr="bar.some.net"
331    else
332        subdir="test"
333        ipaddr="192.168.2.48"
334    fi
335
336    echo Save current software...
337    ssh -p 22432 $ipaddr "rm -rf /gate_debians.prev"
338    ssh -p 22432 $ipaddr "mv /gate_debians /gate_debians.prev"
339    ssh -p 22432 $ipaddr "mkdir /gate_debians"
340    echo Copy new software to the gateway...
341    scp -P 22432 $buildroot/*.deb $ipaddr:/gate_debians
342    echo Install new software...
343    ssh -p 22432 $ipaddr "nohup /usr/local/bin/vpp-swupdate > /dev/null 2>&1 &"
344
345    for i in 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
346    do
347        echo Wait for $i seconds...
348        sleep 1
349    done
350
351    echo Try to access the device...
352
353    ssh -p 22432 -o ConnectTimeout=10 $ipaddr "tail -20 /var/log/syslog | grep Ping"
354    if [ $? == 0 ] ; then
355        echo Access test OK...
356    else
357        echo Access failed, wait for configuration restoration...
358        for i in 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
359        do
360            echo Wait for $i seconds...
361            sleep 1
362        done
363        echo Retry access test
364        ssh -p 22432 -o ConnectTimeout=10 $ipaddr "tail -20 /var/log/syslog | grep Ping"
365        if [ $? == 0 ] ; then
366            echo Access test OK, check syslog on the device
367            exit 1
368        else
369            echo Access test still fails, manual intervention required.
370            exit 2
371        fi
372    fi
373
374    exit 0
375
376 Target script
377 ~~~~~~~~~~~~~
378
379 .. code-block:: c
380
381    #!/bin/bash
382
383    logger "About to update vpp software..."
384    cd /gate_debians
385    service vpp stop
386    sudo dpkg -i *.deb >/dev/null 2>&1 &
387    sleep 20
388    logger "Ping connectivity test..."
389    for i in 1 2 3 4 5 6 7 8 9 10
390    do
391        ping -4 -c 1 yahoo.com
392        if [ $? == 0 ] ; then
393            logger "Ping test OK..."
394            exit 0
395        fi
396    done
397
398    logger "Ping test NOT OK, restore old software..."
399    rm -rf /gate_debians
400    mv /gate_debians.prev /gate_debians
401    cd /gate_debians
402    nohup sudo dpkg -i *.deb >/dev/null 2>&1 &
403    sleep 20
404    logger "Repeat connectivity test..."
405    for i in 1 2 3 4 5 6 7 8 9 10
406    do
407        ping -4 -c 1 yahoo.com
408        if [ $? == 0 ] ; then
409            logger "Ping test OK after restoring old software..."
410            exit 0
411        fi
412    done
413
414    logger "Ping test FAIL after restoring software, manual intervention required"
415    exit 2
416
417 Note that the target script **requires** that the user id which invokes
418 it will manage to “sudo dpkg …” without further authentication. If
419 you’re uncomfortable with the security implications of that requirement,
420 you’ll need to solve the problem a different way. Strongly suggest
421 configuring sshd as described above to minimize risk.
422
423 Testing new software
424 --------------------
425
426 If you frequently test new home gateway software, it may be handy to set
427 up a test gateway behind your production gateway. This testing
428 methodology reduces complaints from family members, to name one benefit.
429
430 Change the inside network (dhcp) subnet from 192.168.1.0/24 to
431 192.168.3.0/24, change the (dhcp) advertised router to 192.168.3.1,
432 reconfigure the vpp tap interface addresses onto the 192.168.3.0/24
433 subnet, and you should be all set.
434
435 This scenario nats traffic twice: first, from the 192.168.3.0/24 network
436 onto the 192.168.1.0/24 network. Next, from the 192.168.1.0/24 network
437 onto the public internet.
438
439 Patches
440 -------
441
442 You'll want this addition to src/vpp/vnet/main.c to add the "service
443 restart isc-dhcp-server” and "service restart vpp" commands:
444
445 .. code-block:: c
446
447    #include <sys/types.h>
448    #include <sys/wait.h>
449
450    static int
451    mysystem (char *cmd)
452    {
453      int rv = 0;
454
455      if (fork())
456        wait (&rv);
457      else
458        execl("/bin/sh", "sh", "-c", cmd);
459
460      if (rv != 0)
461        clib_unix_warning ("('%s') child process returned %d", cmd, rv);
462      return rv;
463    }
464
465    static clib_error_t *
466    restart_isc_dhcp_server_command_fn (vlib_main_t * vm,
467                                        unformat_input_t * input,
468                                        vlib_cli_command_t * cmd)
469    {
470      int rv;
471
472      /* Wait a while... */
473      vlib_process_suspend (vm, 2.0);
474
475      rv = mysystem("/usr/sbin/service isc-dhcp-server restart");
476
477      vlib_cli_output (vm, "Restarted the isc-dhcp-server, status %d...", rv);
478      return 0;
479    }
480
481    VLIB_CLI_COMMAND (restart_isc_dhcp_server_command, static) =
482    {
483      .path = "service restart isc-dhcp-server",
484      .short_help = "restarts the isc-dhcp-server",
485      .function = restart_isc_dhcp_server_command_fn,
486    };
487
488    static clib_error_t *
489    restart_dora_tunnels_command_fn (vlib_main_t * vm,
490                                     unformat_input_t * input,
491                                     vlib_cli_command_t * cmd)
492    {
493      int rv;
494
495      /* Wait three seconds... */
496      vlib_process_suspend (vm, 3.0);
497
498      rv = mysystem ("/usr/sbin/service dora restart");
499
500      vlib_cli_output (vm, "Restarted the dora tunnel service, status %d...", rv);
501      return 0;
502    }
503
504    VLIB_CLI_COMMAND (restart_dora_tunnels_command, static) =
505    {
506      .path = "service restart dora",
507      .short_help = "restarts the dora tunnel service",
508      .function = restart_dora_tunnels_command_fn,
509    };
510
511    static clib_error_t *
512    restart_vpp_service_command_fn (vlib_main_t * vm,
513                                    unformat_input_t * input,
514                                    vlib_cli_command_t * cmd)
515    {
516      (void) mysystem ("/usr/sbin/service vpp restart");
517      return 0;
518    }
519
520    VLIB_CLI_COMMAND (restart_vpp_service_command, static) =
521    {
522      .path = "service restart vpp",
523      .short_help = "restarts the vpp service, be careful what you wish for",
524      .function = restart_vpp_service_command_fn,
525    };
526
527 Using the time-based mac filter plugin
528 --------------------------------------
529
530 If you need to restrict network access for certain devices to specific
531 daily time ranges, configure the "mactime" plugin. Add it to the list of
532 enabled plugins in /etc/vpp/startup.conf, then enable the feature on the
533 NAT "inside" interfaces:
534
535 .. code-block:: c
536
537    bin mactime_enable_disable GigabitEthernet0/14/0
538    bin mactime_enable_disable GigabitEthernet0/14/1
539    ...
540
541 Create the required src-mac-address rule database. There are 4 rule
542 entry types:
543
544 -  allow-static - pass traffic from this mac address
545 -  drop-static - drop traffic from this mac address
546 -  allow-range - pass traffic from this mac address at specific times
547 -  drop-range - drop traffic from this mac address at specific times
548
549 Here are some examples:
550
551 .. code-block:: c
552
553    bin mactime_add_del_range name alarm-system mac 00:de:ad:be:ef:00 allow-static
554    bin mactime_add_del_range name unwelcome mac 00:de:ad:be:ef:01 drop-static
555    bin mactime_add_del_range name not-during-business-hours mac <mac> drop-range Mon - Fri 7:59 - 18:01
556    bin mactime_add_del_range name monday-busines-hours mac <mac> allow-range Mon 7:59 - 18:01