Network Configuration

The first section of this page describes the simplest possible setup for a standalone terminal, the rest of the page describes how to setup more complex Plan 9 network.


To configure your network connection on a standalone terminal you only need to call ipconfig(8) and run ndb/dns -r.

If you have DHCP just run:


Or to explicitly set the configuration:

	ip/ipconfig -g <your-gateway> ether /net/ether0 <your-ip-address> <your-subnet-mask>

After calling ipconfig make sure to run ndb/dns -r to enable dns resolution.

To make this configuration permanent edit your /rc/bin/termrc commenting out and editing(if needed) the corresponding lines that call ipconfig(8).

You can use ip/ping to test that your network connection is working properly. If you have problems see the "troubleshooting" section below.


Plan 9 uses a single database for storing all the network-related configuration information in the system.

The database stores the configuration for machines specifically identifiable by the local installation, default configurations for machines in particular subnets, domain name resolution information, and mappings between TCP service names and port numbers among other things.

The database is assembled from a number of text files bearing a particular record structure.

The default root of the database is the text file /lib/ndb/local. The most important entry in that file is the ``database='' entry, which specifies a list of other files to include. For example,


It is from the contents of this file and those in the list that the database is assembled. These files are typically used by ndb/cs commands in the startup scripts(e.g. /rc/bin/cpurc).

Conventionally, the file /lib/ndb/common is for standard port definitions and the like; the other files hold actual system configuration.


Lexically, a record is an unindented line followed by a series of indented lines. Thus an unindented line, a blank line, or a comment line (one beginning with #) ends a record.

Semantically, a record is a series of ``key=value'' tuples. Tuples on the same line bind slightly more tightly than tuples on different lines, but usually that's not important.

An example record is:

	ip= ip= sys=lusitania ether=0060088bc416

This record defines a system named ``lusitania'' with a specified ethernet address, two IP addresses, and a fully qualified domain name. The ``proto=il'' tuple indicates that the system speaks IL, the Plan 9 transport protocol of choice. By default, systems are assumed only to speak TCP.

Other useful attributes include:

	auth           default Plan 9 authentication server
	cpu            default Plan 9 cpu server
	dns            default DNS server (can be more than one)
	dnsdomain      default DNS domain suffix (can be more than one)
	fs             default Plan 9 file server
	ipgw           IP gateway
	ipmask         IP network mask
	ipsubmask      IP subnetwork mask
	ntp            default NTP server
	nntp           default NNTP server
	smtp           default SMTP server


Most information in the database is not stored in each system's record. Instead, the database query function ndbipinfo (see ndb(2)) and its simple command-line interface ndb/ipquery (see ndb(8)) understand about the hierarchy of IP networks.

When an attribute, say `fs', is needed for a system, the query routines start by looking up that system's network database record. If it has an fs= entry, ndbipinfo returns that value. Otherwise, ndbipinfo notes the system's IP address and walks down the IP hierarchy through the database, starting with the default IP network for the address.

Specifically, it starts with the default IP mask for the address, and'ing it with the IP address to find the default IP network. Suppose our address is, as above. The default IP mask for the address is, so the default IP network is

Ndbipinfo looks for an ip= entry with an ipmask= entry. Suppose we find

	ipnet=ten-net ip= ipmask=

The entry says that the network is composed of smaller subnetworks with mask, so we look for an entry for IP network with the appropriate mask. Suppose we find (the value in the ipnet= tuple is irrelevant)

	ipnet=my-net ip= ipmask=

Since there's no ipsubmask entry, we stop the walk, returning ``my-other-fs'', as it is the fs= entry for the smallest subnet we found. Note that the my-net record entry trumps the ten-net record entry, just as an fs= entry in the lusitania record would trump both of them. If we hadn't found the fs= entry in my-net, we would have used the ten-net one.

The program ndb/ipquery (see ndb(8)) is good for testing that you have your network set up as you want, and that the IP hierarchy walks are happening as expected.

The default IP submasks are determined by the first number in the address:

	224-239     These are reserved for multicast addresses
	240-255     These are reserved for future use

(This is an internet standard, not a Plan 9 one.)


Having read the preceding sections you can begin to define the layout of your network. An example configuration exists at /lib/ndb/local.complicated. A minimal configuration is presented here.


ipnet=mynetwork ip= ipmask=

ip= sys=mauretania
ip= sys=aquitania

In this example we'll setup up the machine 'mauretania' as our first Plan 9 machine and make it the default authentication server for our 192.168.0.x subnet. We'll give our machine the IP address

If you don't intend to have internet connectivity you may omit the ipgw and dns items.


Note that above we have defined two systems, one is 'mauretania', the other is called 'aquitania'. How does Plan 9 determine our machine is supposed to be 'mauretania'? The answer is ip/ipconfig.

When a Plan 9 machine boots, it runs the configuration script /rc/bin/termrc or /rc/bin/cpurc, depending on whether it is a terminal or a CPU server.

In /rc/bin/termrc you will find the line

ip/ipconfig >/dev/null >[2=1]

This line causes the machine to look for a DHCP server to supply it with configuration information. You can set up a Plan 9 CPU/authentication server to run a DHCP server. When you do this the server will look up it's network database and serve out the configuration defaults.

Nevertheless, there isn't yet enough information there to give a specific machine a fixed IP. One way of doing this is to bind a specific configuration to a specific network card's MAC address. Each physical network card is given an unique MAC address when manufactured. You can find out your card's MAC address by typing the line

	cat /net/ether0/addr

(If there isn't a /net/ether0 directory then Plan 9 did not find an ethernet card on your system.) You can now add the MAC address as an attribute of the configuration line in the ndb like

ip= sys=mauretania ether=abc12345def

where 'abc12345def' is the MAC address. Of course if there isn't a Plan 9 DHCP server on the network, this method won't work. When setting up your first Plan 9 machine, you can modify the ip/ipconfig line to specify a specific gateway, ip, and ip-mask to use.

ip/ipconfig -g ether /net/ether0

You now have enough information to follow the instructions for Configuring a Standalone CPU Server. It will guide you in setting up a system suitable as any combination of CPU server, Authentication server, DHCP server, and even a light-weight kfs (file) server. For a proper file server see Installing a Plan 9 file server.


If ipconfig gives an error of the form

ip/ipconfig: binding device: '/net/ether0' cs: file does not exist

it indicates that the kernel has not detected your network card. For a PC, make sure that your plan9.ini(8) file specifies the proper network driver. If that doesn't help, it could be that the proper network driver is not compiled into the kernel that you're using. See Compiling kernels for information on how to make a new kernel.

If after installing a fossil+venti system you get an error message like

ndb/dns: can't read my ip address

you might want to edit the /rc/bin/termrc to omit the test conditions for both ip/ipconfig and ndb/dns - the relevant section should just read something like:

ip/ipconfig >/dev/null >[2=1]
ndb/dns -rf $NDBFILE


ndb/query and ndb/ipquery look directly in the ndb files. ndb/query does simple direct queries based on the given attribute and value, ndb/ipquery searches more extensively up through the subnet hierarchy. They are both good tools to check basic functioning of an ndb file. If they don't produce sensible results, it's unlikely cs will. ndb/query and (probably) ndb/ipquery do not talk to ndb/cs or ndb/dns at all.

ndb/csquery simply opens /net/cs and speaks its protocol, which expects strings of the form

and replies with translations of them:

	term% ndb/csquery
	> net!!9fs
cs relies on dns to translate domain names to ip addresses. It does not expect a plain name such as `p9'. It translates
dial(2) addresses.

There's a special case that's also useful in checking whether your host, subnet and net defaults for services are reasonable.

looks for the given attribute `attr' through the subnet hierarchy starting at the host and working up. Thus the dial(2) string `net!$fs!9fs' dials the (default) file server configured for the current node, and the translation can be checked by:
	term% ndb/csquery
	> net!$fs!9fs
i don't know without a lot of grepping how much the $attr is used now but it is used to find an authentication server in the absence of an authdom (see /sys/src/libauthsrv/authdial.c). It doesn't really matter because the point here is that $xyz can be used to check that cs gives a sensible value for xyz for the current node.

ndb/dnsquery opens /net/dns and uses its protocol:

	> ns ns ns ns ns ns ns
	> ip


To boot a machine using PXE set add an entry to /lib/ndb/local something like:

sys=doris ether=03294ea93902

The intial boot via DHCP will discover the ether config and download 9pxeload. This will then pull down its plan9.ini file which it expects to find in the file:

	/cfg/pxe/<mac address>.

bootstrap then continues as usual.


Dialup modem config, DNSMASQ, ipconfig(8), ndb(8), ndb(6), The Organization of Networks in Plan 9 ( /sys/doc/net/ )




explain items in cpurc

ndb/cs ndb/dns ip/dhcp ip/tftp aux/timesync /net/ndb auth/keyfs aux/listen