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