Command Line Reference

This walk-through tutorial for the command line interface is designed to give you a basic working knowledge of how the daemon services are ogranized for managing the devices on your network.

Login

Launch the DHCP interactive command-console with this command:

$ /usr/bin/dhcpti

If you get a password prompt enter your password. If there is no system password just press [ENTER].

Using Commands

In the command console you can enter interactive commands that the server executes, and see the results on screen.

❗ Many command that you enter will be multiple lines. The lines you type in are not sent to the server until you press [ENTER] on a blank line. This is abbreviated in the examples below with [EE], which means to press [ENTER] twice in succession.

Choose a DHCP server context

Once logged in, select a DHCP engine to work with:

set_context=4 [EE]

code=ack

or

set_context=6 [EE]

code=ack

Choose 4 for DHCPv4 or 6 for DHCPv6. I'll use DHCPv4 for this tutorial.

Very few commands can be issued until a context has been chosen. You can switch between contexts at any time by issuing a new set_context command.

Select, Insert, Update, Delete

Most of the operations you perform in the command window will be a subset of SQL. Records are stored in an SQL database, and made available to you using a command syntax that closely maps to the underlying SQL, with some limitations.

For each type of record in the database, there are a corresponding set of select/insert/update/delete commands. These commands have the form:

where object is the name of the object type you're referencing. Object types are:

Most select/insert/update/delete commands also take (in some cases require) an SQL where clause. In particular, the delete_object command refuses to operate without a where clause to limit its scope.

By default, a select_object command returns a maximum of 50 records. You can execute a select_next_object command to see more records.

Many of the select_object commands can be abbreviated by using the first letter of each word in the command. For example, sap is short for select_address_pool, and snxap is short for select_next_address_pool.

The next few sections walk you through these commands, and explain the purpose of each type of record.

Viewing Accounts

Every DHCP client has a device account on the DHCP server. The server comes with two built-in accounts; let's view them:

select_account [EE]

acl=CM,DOCSIS 2 cable modem,Data.Basic
class=device4
description=
domains=Administrators,Observers,API
enabled=true
mod_time=Sun Dec  3 19:02:43 2023
name=01-E4-83-99-75-11-F8
oid=4608
reconfig_time=Thu Jan  1 00:00:00 1970
reprov_time=Thu Jan  1 00:00:00 1970
subscriber_id=3125
subscription_id=
-
acl=CM,DOCSIS 2 cable modem,Data.Basic
class=device4
description=
domains=Administrators,Observers,API
enabled=true
mod_time=Sun Dec  3 19:02:43 2023
name=01-E4-83-99-1F-FE-9A
oid=4720
reconfig_time=Thu Jan  1 00:00:00 1970
reprov_time=Thu Jan  1 00:00:00 1970
subscriber_id=0037
subscription_id=
-
code=ack

This response contains two records, where each record is delimited with a '-' character on a line by itself. The entire response ends with the server's response code.

The records shown are device accounts. The account contains the DHCP client identifier (typically 01 and the device MAC address) as well as other associated information. The acl shows what domains (aka groups) this device is a member of, while the domains defines the permissions for the record itself.

Note that every account has a unique object identifier associated with it (oid=nnnn). Object identifiers uniquely identify records in the DHCP server.

Domains

The DHCP server has the notion of domains. Domains are groups, where each group contains a set of members. Members can be devices (accounts) or resources (pools, policies, etc). To give a specific account access to a specific address pool, for example, you would first create a domain, then add both the account and the address pool to that domain.

Let's look at some domains in this server:

select_domain [EE]

description=All devices on your network
domains=Administrators,Observers
groups=All
mdata=
mod_time=Tue Mar 29 15:12:16 2023
name=All devices
oid=2
priority=10000
type=device
-
description=All cable modems belong to this domain.
domains=Administrators,Observers
groups=All,Device Class
mdata=
mod_time=Tue Mar 29 15:12:16 2023
name=CM
oid=1824
priority=1000
type=device
-
code=ack

We show two domains in this output: All and CM.

The All domain is built-in, and every device on your network belongs to this domain.

The CM domain is for cable modem devices. You can assign a device account to this domain manually, but that is normally handled automatically by a rule in the system that analyzes and classifies devices when they are first seen on your network.

Next, let's see how accounts are related to domains.

Access Controls

Access controls dictate the connection between accounts and domains. Let's start by looking at the default access controls to see how they work:

select_access_control [EE]

access_id=0
domain_id=0
pk=3
rights=read,write,execute
-
access_id=1
domain_id=1
pk=4
rights=execute
-
access_id=3
domain_id=3
pk=6
rights=execute
-
code=ack

There are three access controls. The first access control states that the account having identifier 0 (access_id=0) belongs to domain having identifier 0 (domain_id=0).

So this first record indicates that the 'Admin' account belongs to the 'Admin' domain. Because of this access control, when the 'Admin' user logs into the server, he will belong to the 'Admin' domain.

Furthermore, this first access control states that the 'Admin' user has read, write and execute permissions on all resources that belong to the 'Admin' domain.

An account may belong to multiple domains simultaneously. In that case there will be multiple records, each having the same access_id field, but different domain_id fields.

The second access control indicates that the 'All nodes' account belongs to the 'All nodes' domain. The interesting part of this access control is the permissions: execute only. This control associates a device account to a domain, and device accounts only ever require execute permission to be able to use a resource. A device account never requires read or write access to a domain, although it's fine to give it those permissions.

The second access control is for DHCPv4 'All nodes', and the third is for DHCPv6 'All nodes'.

Options

Let's turn our attention to a DHCP-server resource: options. Options describe the data that can be carried to and from a DHCP server. The server comes pre-configured with many standard DHCP options. Let's see some:

select_option [EE]

arrayed=true
description=A list of IP addresses, in preferential order, of X Window System Font servers available to the device.
domains=Admin,All nodes
max_instances=1
name=X Window system font servers
null_terminated=false
pk=51
signed=false
tag=48
type=ipaddress
user_definable=allowed
vendor_id=0
vendor_id_tag=2147483647
-
arrayed=true
description=A list of IP addresses, in preferential order, of systems that are running the X Window System Display Manager and are available to the device.
domains=Admin,All nodes
max_instances=1
name=X Window system display managers
null_terminated=false
pk=52
signed=false
tag=49
type=ipaddress
user_definable=allowed
vendor_id=0
vendor_id_tag=2147483647
-
code=ack

This output is from the DHCPv4 protocol context, because that's the protocol context I chose for this example (set_context=4). Further, it's only the last two options returned by the select statement. To see more options, execute:

select_next_option [EE]

If you switch to the DHCPv6 context, you'll see a different set of options. That's one way a context works; it only shows records relevant for the currently chosen DHCP protocol. At this point, let's introduce a simple where clause to locate a specific record:

select_option
where=T.name='Interface MTU' [EE]

arrayed=false
description=The Maximum Transmission Unit the device should use for this interface.
domains=Admin,All nodes
max_instances=1
name=Interface MTU
null_terminated=false
pk=29
signed=false
tag=26
type=16bit
unit=bytes
user_definable=allowed
vendor_id=0
vendor_id_tag=2147483647
-
code=ack

As you can see, the where clause limited our result set to one record only.

Address Pools

Address pools are ranges of IP addresses the server can lease to clients. Let's see the address pools defined:

select_address_pool [EE]

code=ack

There are no address pools defined. Let's insert one:

insert_address_pool
name=test
relay=0.0.0.0
rangestart=10.0.0.1
rangestop=10.255.255.254
prefix_len=8
valid_lt=3000
pref_lt=1000 [EE]

code=ack

This address pool record was accepted. If you get the error message 'Cannot insert address pool. Incorrect ip address type for key ''relay''.', it means you tried to insert an IPv4 address pool while operating in a DHCPv6 context. To insert an IPv6 address pool:

set_context=6[EE]

code=ack

insert_address_pool
name=test
relay=::
rangestart=dead:dead:aaaa::1000
rangestop=dead:dead:aaaa::4730
prefix_len=64
valid_lt=3000
pref_lt=1000 [EE]

code=ack

Two address pools in the same context cannot have the same name. In the two cases above, we entered the same name for the address pools, but in two different DHCP contexts.

There are many more fields in an address pool, but we only provided the server with the minimum required. Let's see all of the fields of an address pool:

select_address_pool [EE]

active=true
allow=
deny=
description=
domains=Admin,All nodes
name=test
option Subnet mask=255.0.0.0
pk=5
pref_lt=1000
prefix=10.0.0.0
prefix_len=8
weight=0
rangestart=10.0.0.1
rangestop=10.255.255.254
relay=0.0.0.0
valid_lt=3000
xrange=
-
code=ack

According to the fields the server provided values for:

...and a few other tidbits

When we created the address pool, we didn't specify which operators and devices had access to the pool. By default, address pool and address binding resources belong to both the 'Admin' and the 'All Nodes' domain. All other resources default to the 'Admin' domain only.

When inserting or updating an address pool (or any other resource), you can specify the domain(s) it belongs to by adding the domains=xxx,yyy key, where xxx and yyy are the names or identifiers of the domains.

You may specify as many or as few domains as you like.

Resources always belong to the Admin domain, regardless of your input.

Policies

Policies are containers that hold sets of options. You can create a policy, place a set of DHCP options into it, and assign that policy to a domain. Clients that are allowed to use that domain will then receive the options defined in the policy. You can assign as many policies as you wish to a domain. Let's insert a new policy called 'Silver', and fill it with a DHCPv4 Boot file option definition:

insert_policy
name=Silver
option Boot file=silver.bin [EE]

code=ack

... and now to see the policy we just created:

select_policy
where=T.name='Silver' [EE]

domains=Admin,All nodes
name=Silver
option Boot file="silver.bin"
pk=4
-
code=ack

Notice that the policy was automatically assigned to 'Admin' and 'All Nodes' domains. Since All Nodes is a device domain that every DHCP client belongs to, then every DHCP client will receive this option from the DHCP server. A more useful example of policies is shown in the Manual Provisioning Example section.

Let's update this policy by adding the Gateways option to it:

update_policy
where=T.name='Silver'
option Gateways=10.0.0.1 [EE]

count=1
code=ack

And now to see our latest changes:

select_policy
where=T.name='Silver' [EE]

domains=Admin,All nodes
name=Silver
option Boot file="silver.bin"
option Gateways=10.0.0.1
pk=4
-
code=ack

If you have many options defined in a policy (or elsewhere, such as an Address Pool), you can delete a specific option by issuing an update command and preceding the option definition with a minus sign (-):

update_policy
where=T.name='Silver'
-option Boot file= [EE]

count=1
code=ack

And to verify that the option was removed:

select_policy
where=T.name='Silver' [EE]

domains=Admin,All nodes
name=Silver
option Gateways=10.0.0.1
pk=4
-
code=ack

Bindings

We've run up the DHCP client and had it lease an address from the pool we just inserted. Let's see the binding:

select_binding [EE]

client_id=01-11-11-11-11-11-11
commit_time=Mon May 21 18:04:25 2007
domains=Admin,All nodes
fixed=false
ipaddr=10.0.0.1
lease_duration=0:50:0
pk=5
protocol=dhcpv4
relay=0.0.0.0
address_pool=test
-
code=ack

The interesting point about the binding record is the domain(s) to which the binding belongs. This binding belongs to 'Admin' and 'All nodes'.

As stated earlier, a resource is always available to the Admin domain. Administrators can always access resources.

This reason this binding belongs to the 'All nodes' domain, however, is because the pool from which the lease was created belonged to the 'All nodes' domain.

A new binding always inherits the domains of the pool from which it was generated. This is an important feature, which is best explained with the note found in the DHCP server's source code at the point a new binding is created:


We use the full set of domain IDs from the address pool, because the pool is essentially telling us which of the identities the client is using to access that resource.

This approach works well for provisioning, because it allows the binding to be "enabled" or "disabled" depending on the identity of the DHCP client.


This means that, provided the DHCP client meets the other basic pool requirements, it will be able to extend an existing lease as long as it still belongs to the same domain as the binding.

By dissociating a DHCP client account from a domain (deleting the Access Control record), you effectively deny the client any access it previously had to resources from that domain, including any existing bindings. This behavior allows you to re-provision an existing managed device by simply changing its domain associations.

Provisioning Basics

A provisioning DHCP server is a DHCP server that can differentiate DHCP clients, DHCP client classes or the roles a DHCP client assumes. It can then assign or verify resources based on this differentiation.

The DHCP server includes a provisioner subsystem that identifies DHCP clients and assigns them to server accounts. Accounts are then associated with domains, and a subset of the server's resources are made available to the client based on the resources that are available to the client's domains.

The provisioner subsystem in Broadband Provisioner® is an application plugin. Different provisioner plugins may identify clients using different schemes. The current version ships with one identification scheme, the M-Provisioner, which identifies DHCP clients based on their MAC addresses (more specifically, their Client Identifier).

The M-Provisioner plugin simply assumes that every DHCP client that communicates with the server will have an account assigned to it, where the account-name is the Client Identifier of the DHCP client. When a DHCP client initiates a transaction with the DHCP server, the M-Provisioner finds the account for this client, looks at the access controls in use for this account, and indicates the domains to which the client has access.

The M-Provisioner also supports auto-provisioning, where DHCP clients that do not have a pre-existing account can be classified at runtime, have their accounts created, and be associated with specific domains. Auto-provisioning is covered in the Automatic Provisioning Example section.

Manual Provisioning Example

Manual provisioning can be tedious, and is generally not recommended for human operators. Your Operational Support Software will normally carry out the tasks associated with manual provisioning, or you'll be using auto-provisioning.

To manually create a DHCP client account that the M-Provisioner can use, let's assume that an Ethernet DHCP client with MAC address 00-A0-24-2F-10-26 will be operating on our network:

insert_account
class=device4
name=01-00-A0-24-2F-10-26
pass= [EE]

code=ack

This step creates a device-type account for the DHCP client. The account name corresponds to the client identifier the DHCP client will use. Note that the M-Provisioner doesn't require its accounts to have passwords, but you have to specify a password when entering an account. In this case, we simply left the password blank.

The next step is to create a domain that we'll use for this one DHCP client only:

insert_domain
class=device4
name=01-00-A0-24-2F-10-26

code=ack

Now, before we can associate the account we created with the domain we created, we need to know the access id of the account and the domain id of the domain. Both operations are shown below:

select_account
where=T.name='01-00-A0-24-2F-10-26' [EE]

class=device4
description=
domains=Admin,All nodes
enabled=true
id=11
name=01-00-A0-24-2F-10-26
pass=
pk=11
-
code=ack

select_domain
where=T.name='01-00-A0-24-2F-10-26' [EE]

class=device4
description=
domains=Admin,All nodes
explicit=false
id=11
name=01-00-A0-24-2F-10-26
pk=11
-
code=ack

❗ You cannot specify the domain id a new domain should use, or the access id a new account should use. The server creates these identifiers for you, and ensures that each identifier is unique.

Now we associate the new account with the new domain:

insert_access_control
access_id=11
domain_id=11
rights=execute [EE]

code=ack

You can verify the new access control by issuing this command:

select_access_control
where=T.access_id=11 [EE]

The server output is not shown here. We now have an account for our DHCP client, and the account is associated with a domain, so what's next? We assign address pools and policies to the domain. The DHCP client will be able to use any address pool and all policies assigned to this client's domain.

To create an address pool and assign it to this DHCP client only, we could issue this command:

insert_address_pool
name=test
relay=0.0.0.0
rangestart=10.0.0.1
rangestop=10.255.255.254
prefix_len=8
valid_lt=3000
pref_lt=1000
domains=01-00-A0-24-2F-10-26

One question that might arise here is "What happens if I want to assign two million clients to this address pool?"

The answer is: that would be the wrong approach. If you want two million clients to be able to use a single address pool, it's far more efficient to create a single domain for those clients, assign the domain to the pool, and to insert two million access controls associating each client to this one domain.

To assign a policy to this domain, create the policy as shown in the Policy section, but also add domains=01-00-A0-24-2F-10-26 to the new record.

Automatic Provisioning Example

The M-Provisioner supports auto-provisioning, where DHCP clients that do not have a pre-existing account can be classified at runtime, have their accounts created, and be associated with specific domains.

Auto-provisioning is useful when you want the DHCP server to make an authoritative decision concerning the resources that should be made available to unknown DHCP clients.

The M-Provisioner supports auto-provisioning through two key=value settings in the /etc/dhcpt/dhcptd.conf file (one for each DHCP protocol version):

auto_provision_domains4='Unknown-v4-CM' auto_provision_domains6='Unknown-v6-CM'

In the simplest case, you state which domain new devices should belong to. If a DHCP client already has an account in this DHCP server, auto-provisioning is not used. For unknown DHCP clients, a new account is created, and a new access control is inserted which associates the new account to the specified domain(s).

In many cases it can be useful to first perform some checks on the DHCP client, and automatically provision different types of clients into different domains. The M-Provisioner supports this by allowing you to use an expression for the auto_provision_domain:

auto_provision_domains4=[ $LEFT($CLASSID(),6) == "docsis" ? "Unknown-v4-CM" : "Unknown-v4-CPE"]

This expression checks the DHCP client's class identifier: If it begins with "docsis", the device account is associated with a domain for unknown DHCPv4 cable modems; otherwise it's associated with a domain for unknown DHCPv4 CPE.

The only requirement of your expression is that it result in one or more text strings naming the domains with which the account should be associated. If a domain doesn't exist, the DHCP client will simply fall into the 'All Nodes' domain, and pick up whatever resources are available to that domain.

You can provision a device into two domains at once by returning two values in your expression. The following example provisions devices into one domain whose name reflects the circuit identifier the device is booting from, and another domain named "Chicago":

auto_provision_domains4=[ $STR($RELAY.CID()), "Chicago" ]

Searching for Data

We've shown some examples of searching for data using the where clause. Here's a more formal description:

The interface exposed by the interactive command shell does not provide you with a direct SQL syntax because you're not searching for records in a table; you're searching for objects, such as an address pool object or an account object.

These objects are stored in the SQL database, but they may span more than one table. For each object, there are a set of fields that belong to that object's primary table, and there are fields that belong to secondary tables.

When specifying a where clause, use the alias T to denote the object's primary table. For searching on secondary tables, use one of the aliases below:

Generally you will search for objects using the T. notation because most interesting fields are in the object's primary table. One exception to this is when searching for an object based on the domains to which it belongs. To search for an address pool that belongs to domain 25, for example, you would use this syntax:

sap
where=DI.DOMAIN_ID IN (25)