---
name: "net_kernel"
section: "3erl"
platform: "linux"
package: "erlang-manpages"
version: "1:25.2.3+dfsg-1+deb12u4"
release: "Debian 12 (Bookworm)"
platforms: ["linux"]
url: "https://new.carta.tech/net_kernel"
---

# net\_kernel(3erl)

Erlang networking kernel.

## NAME

net\_kernel - Erlang networking kernel.

## DESCRIPTION

The net kernel is a system process, registered as *net\_kernel*, which must be operational for distributed Erlang to work. The purpose of this process is to implement parts of the BIFs *spawn/4* and *spawn\_link/4*, and to provide monitoring of the network.

An Erlang node is started using command-line flag *-name* or *-sname*:

```
$ erl -sname foobar
```

It is also possible to call *net\_kernel:start(foobar, #{})* directly from the normal Erlang shell prompt:

```
1> net_kernel:start(foobar, #{name_domain => shortnames}).
{ok,<0.64.0>}
(foobar@gringotts)2>
```

If the node is started with command-line flag *-sname*, the node name is *foobar@Host*, where *Host* is the short name of the host (not the fully qualified domain name). If started with flag *-name*, the node name is *foobar@Host*, where *Host* is the fully qualified domain name. For more information, see *erl*.

Normally, connections are established automatically when another node is referenced. This functionality can be disabled by setting Kernel configuration parameter *dist\_auto\_connect* to *never*, see *[kernel(7)](/kernel/7.md)*. In this case, connections must be established explicitly by calling *connect\_node/1*.

Which nodes that are allowed to communicate with each other is handled by the magic cookie system, see section Distributed Erlang in the Erlang Reference Manual.

**Warning:**

Starting a distributed node without also specifying *-proto\_dist inet\_tls* will expose the node to attacks that may give the attacker complete access to the node and in extension the cluster. When using un-secure distributed nodes, make sure that the network is configured to keep potential attackers out. See the  Using SSL for Erlang Distribution User's Guide for details on how to setup a secure distributed node.

## EXPORTS

```
allow(Nodes) -> ok | error
```

Types:

Nodes = \[node()\]\

Permits access to the specified set of nodes.

Before the first call to *allow/1*, any node with the correct cookie can be connected. When *allow/1* is called, a list of allowed nodes is established. Any access attempts made from (or to) nodes not in that list will be rejected.

Subsequent calls to *allow/1* will add the specified nodes to the list of allowed nodes. It is not possible to remove nodes from the list.

Returns *error* if any element in *Nodes* is not an atom.

```
connect_node(Node) -> boolean() | ignored
```

Types:

Node = node()\

Establishes a connection to *Node*. Returns *true* if a connection was established or was already established or if *Node* is the local node itself. Returns *false* if the connection attempt failed, and *ignored* if the local node is not alive.

```
get_net_ticktime() -> Res
```

Types:

Res = NetTicktime \| {ongoing\_change\_to, NetTicktime} \| ignored\
 NetTicktime = integer() \>= 1\

Returns currently used net tick time in seconds. For more information see the *net\_ticktime* *[kernel(7)](/kernel/7.md)* parameter.

Defined return values (*Res*):

- ***NetTicktime*:**

  *net\_ticktime* is *NetTicktime* seconds.

- ***{ongoing\_change\_to, NetTicktime}*:**

  *net\_kernel* is currently changing *net\_ticktime* to *NetTicktime* seconds.

- ***ignored*:**

  The local node is not alive.

```
getopts(Node, Options) ->
           {ok, OptionValues} | {error, Reason} | ignored
```

Types:

Node = node()\
 Options = \[inet:socket\_getopt()\]\
 OptionValues = \[inet:socket\_setopt()\]\
 Reason = inet:posix() \| noconnection\

Get one or more options for the distribution socket connected to *Node*.

If *Node* is a connected node the return value is the same as from *inet:getopts(Sock, Options)* where *Sock* is the distribution socket for *Node*.

Returns *ignored* if the local node is not alive or *{error, noconnection}* if *Node* is not connected.

```
get_state() ->
             #{started => no | static | dynamic,
               name => atom(),
               name_type => static | dynamic,
               name_domain => shortnames | longnames}
```

Get the current state of the distribution for the local node.

Returns a map with (at least) the following key-value pairs:

- ***started =\> Started*:**

  Valid values for *Started*:

  - ***no*:**

    The distribution is not started. In this state none of the other keys below are present in the map.

  - ***static*:**

    The distribution was started with command line arguments *-name* or *-sname*.

  - ***dynamic*:**

    The distribution was started with *net\_kernel:start/1* and can be stopped with *net\_kernel:stop/0*.

- ***name =\> Name*:**

  The name of the node. Same as returned by *erlang:node/0* except when *name\_type* is *dynamic* in which case *Name* may be *undefined* (instead of *nonode@nohost*).

- ***name\_type =\> NameType*:**

  Valid values for *NameType*:

  - ***static*:**

    The node has a static node name set by the node itself.

  - ***dynamic*:**

    The distribution was started in  dynamic node name mode, and will get its node name assigned from the first node it connects to. If key *name* has value *undefined* that has not happened yet.

- ***name\_domain =\> NameDomain*:**

  Valid values for *NameDomain*:

  - ***shortnames*:**

    The distribution was started to use node names with a short host portion (not fully qualified).

  - ***longnames*:**

    The distribution was started to use node names with a long fully qualified host portion.

```
monitor_nodes(Flag) -> ok | Error
```

```
monitor_nodes(Flag, Options) -> ok | Error
```

Types:

Flag = boolean()\
 Options = OptionsList \| OptionsMap\
 OptionsList = \[ListOption\]\
 ListOption = \
\
     connection\_id \| {node\_type, NodeType} \| nodedown\_reason\
 OptionsMap = \
\
     \#{connection\_id =\> boolean(),\
\
       node\_type =\> NodeType,\
\
       nodedown\_reason =\> boolean()}\
 NodeType = visible \| hidden \| all\
 Error = error \| {error, term()}\

The calling process subscribes or unsubscribes to node status change messages. A *nodeup* message is delivered to all subscribing processes when a new node is connected, and a *nodedown* message is delivered when a node is disconnected.

If *Flag* is *true*, a new subscription is started. If *Flag* is *false*, all previous subscriptions started with the same *Options* are stopped. Two option lists are considered the same if they contain the same set of options.

Delivery guarantees of *nodeup*/*nodedown* messages:

- \*

  *nodeup* messages are delivered before delivery of any signals from the remote node through the newly established connection.

- \*

  *nodedown* messages are delivered after all the signals from the remote node over the connection have been delivered.

- \*

  *nodeup* messages are delivered after the corresponding node appears in results from *erlang:nodes()*.

- \*

  *nodedown* messages are delivered after the corresponding node has disappeared in results from *erlang:nodes()*.

- \*

  As of OTP 23.0, a *nodedown* message for a connection being taken down will be delivered before a *nodeup* message due to a new connection to the same node. Prior to OTP 23.0, this was not guaranteed to be the case.

The format of the node status change messages depends on *Options*. If *Options* is the empty list or if *net\_kernel:monitor\_nodes/1* is called, the format is as follows:

```
{nodeup, Node} | {nodedown, Node}
  Node = node()
```

When *Options* is the empty map or empty list, the caller will only subscribe for status change messages for visible nodes. That is, only nodes that appear in the result of *erlang:nodes/0*.

If *Options* equals anything other than the empty list, the format of the status change messages is as follows:

```
{nodeup, Node, Info} | {nodedown, Node, Info}
  Node = node()
  Info = #{Tag => Val} | [{Tag, Val}]
```

*Info* is either a map or a list of 2-tuples. Its content depends on *Options*. If *Options* is a map, *Info* will also be a map. If *Options* is a list, *Info* will also be a list.

When *Options* is a map, currently the following associations are allowed:

- ***connection\_id =\> boolean()*:**

  If the value of the association equals *true*, a *connection\_id =\> ConnectionId* association will be included in the *Info* map where *ConnectionId* is the connection identifier of the connection coming up or going down. For more info about this connection identifier see the documentation of erlang:nodes/2.

- ***node\_type =\> NodeType*:**

  Valid values for *NodeType*:

  - ***visible*:**

    Subscribe to node status change messages for visible nodes only. The association *node\_type =\> visible* will be included in the *Info* map.

  - ***hidden*:**

    Subscribe to node status change messages for hidden nodes only. The association *node\_type =\> hidden* will be included in the *Info* map.

  - ***all*:**

    Subscribe to node status change messages for both visible and hidden nodes. The association *node\_type =\> visible \| hidden* will be included in the *Info* map.

  If no *node\_type =\> NodeType* association is included in the *Options* map, the caller will subscribe for status change messages for visible nodes only, but *no*  *node\_type =\> visible* association will be included in the *Info* map.

- ***nodedown\_reason =\> boolean()*:**

  If the value of the association equals *true*, a *nodedown\_reason =\> Reason* association will be included in the *Info* map for *nodedown* messages.

  *Reason* can, depending on which distribution module or process that is used, be any term, but for the standard TCP distribution module it is one of the following:

  - ***connection\_setup\_failed*:**

    The connection setup failed (after *nodeup* messages were sent).

  - ***no\_network*:**

    No network is available.

  - ***net\_kernel\_terminated*:**

    The *net\_kernel* process terminated.

  - ***shutdown*:**

    Unspecified connection shutdown.

  - ***connection\_closed*:**

    The connection was closed.

  - ***disconnect*:**

    The connection was disconnected (forced from the current node).

  - ***net\_tick\_timeout*:**

    Net tick time-out.

  - ***send\_net\_tick\_failed*:**

    Failed to send net tick over the connection.

  - ***get\_status\_failed*:**

    Status information retrieval from the *Port* holding the connection failed.

When *Options* is a list, currently *ListOption* can be one of the following:

- ***connection\_id*:**

  A *{connection\_id, ConnectionId}* tuple will be included in *Info* where *ConnectionId* is the connection identifier of the connection coming up or going down. For more info about this connection identifier see the documentation of erlang:nodes/2.

- ***{node\_type, NodeType}*:**

  Valid values for *NodeType*:

  - ***visible*:**

    Subscribe to node status change messages for visible nodes only. The tuple *{node\_type, visible}* will be included in the *Info* list.

  - ***hidden*:**

    Subscribe to node status change messages for hidden nodes only. The tuple *{node\_type, hidden}* will be included in the *Info* list.

  - ***all*:**

    Subscribe to node status change messages for both visible and hidden nodes. The tuple *{node\_type, visible \| hidden}* will be included in the *Info* list.

  If no *{node\_type, NodeType}* option has been given. The caller will subscribe for status change messages for visible nodes only, but *no*  *{node\_type, visible}* tuple will be included in the *Info* list.

- ***nodedown\_reason*:**

  The tuple *{nodedown\_reason, Reason}* will be included in the *Info* list for *nodedown* messages.

  See the documentation of the *nodedown\_reason =\> boolean()* association above for information about possible *Reason* values.

Example:

```
(a@localhost)1> net_kernel:monitor_nodes(true, #{connection_id=>true, node_type=>all, nodedown_reason=>true}).
ok
(a@localhost)2> flush().
Shell got {nodeup,b@localhost,
                  #{connection_id => 3067552,node_type => visible}}
Shell got {nodeup,c@localhost,
                  #{connection_id => 13892107,node_type => hidden}}
Shell got {nodedown,b@localhost,
                    #{connection_id => 3067552,node_type => visible,
                      nodedown_reason => connection_closed}}
Shell got {nodedown,c@localhost,
                    #{connection_id => 13892107,node_type => hidden,
                      nodedown_reason => net_tick_timeout}}
Shell got {nodeup,b@localhost,
                  #{connection_id => 3067553,node_type => visible}}
ok
(a@localhost)3>
```

```
set_net_ticktime(NetTicktime) -> Res
```

```
set_net_ticktime(NetTicktime, TransitionPeriod) -> Res
```

Types:

NetTicktime = integer() \>= 1\
 TransitionPeriod = integer() \>= 0\
 Res = \
\
     unchanged \| change\_initiated \|\
\
     {ongoing\_change\_to, NewNetTicktime}\
 NewNetTicktime = integer() \>= 1\

Sets *net\_ticktime* (see *[kernel(7)](/kernel/7.md)*) to *NetTicktime* seconds. *TransitionPeriod* defaults to *60*.

Some definitions:

- **Minimum transition traffic interval (*MTTI*):**

  *minimum(NetTicktime, PreviousNetTicktime)\*1000 div 4* milliseconds.

- **Transition period:**

  The time of the least number of consecutive *MTTI*s to cover *TransitionPeriod* seconds following the call to *set\_net\_ticktime/2* (that is, ((*TransitionPeriod\*1000 - 1) div MTTI + 1)\*MTTI* milliseconds).

If *NetTicktime \< PreviousNetTicktime*, the *net\_ticktime* change is done at the end of the transition period; otherwise at the beginning. During the transition period, *net\_kernel* ensures that there is outgoing traffic on all connections at least every *MTTI* millisecond.

**Note:**

The *net\_ticktime* changes must be initiated on all nodes in the network (with the same *NetTicktime*) before the end of any transition period on any node; otherwise connections can erroneously be disconnected.

Returns one of the following:

- ***unchanged*:**

  *net\_ticktime* already has the value of *NetTicktime* and is left unchanged.

- ***change\_initiated*:**

  *net\_kernel* initiated the change of *net\_ticktime* to *NetTicktime* seconds.

- ***{ongoing\_change\_to, NewNetTicktime}*:**

  The request is *ignored* because *net\_kernel* is busy changing *net\_ticktime* to *NewNetTicktime* seconds.

```
setopts(Node, Options) -> ok | {error, Reason} | ignored
```

Types:

Node = node() \| new\
 Options = \[inet:socket\_setopt()\]\
 Reason = inet:posix() \| noconnection\

Set one or more options for distribution sockets. Argument *Node* can be either one node name or the atom *new* to affect the distribution sockets of all future connected nodes.

The return value is the same as from *inet:setopts/2* or *{error, noconnection}* if *Node* is not a connected node or *new*.

If *Node* is *new* the *Options* will then also be added to kernel configuration parameters inet\_dist\_listen\_options and inet\_dist\_connect\_options.

Returns *ignored* if the local node is not alive.

```
start(Name, Options) -> {ok, pid()} | {error, Reason}
```

Types:

Options = \
\
     \#{name\_domain =\> NameDomain,\
\
       net\_ticktime =\> NetTickTime,\
\
       net\_tickintensity =\> NetTickIntensity,\
\
       dist\_listen =\> boolean(),\
\
       hidden =\> boolean()}\
 Name = atom()\
 NameDomain = shortnames \| longnames\
 NetTickTime = integer() \>= 1\
 NetTickIntensity = 4..1000\
 Reason = {already\_started, pid()} \| term()\

Turns a non-distributed node into a distributed node by starting *net\_kernel* and other necessary processes.

If *Name* is set to *undefined* the distribution will be started to request a dynamic node name from the first node it connects to. See  Dynamic Node Name. Setting *Name* to *undefined* implies options *dist\_listen =\> false* and *hidden =\> true*.

Currently supported options:

- ***name\_domain =\> NameDomain*:**

  Determines the host name part of the node name. If *NameDomain* equals *longnames*, fully qualified domain names will be used which also is the default. If *NameDomain* equals *shortnames*, only the short name of the host will be used.

- ***net\_ticktime =\> NetTickTime*:**

  *Net tick time*  to use in seconds. Defaults to the value of the *net\_ticktime* *[kernel(7)](/kernel/7.md)* parameter. For more information about *net tick time* , see the *kernel* parameter. However, note that if the value of the *kernel* parameter is invalid, it will silently be replaced by a valid value, but if an invalid *NetTickTime* value is passed as option value to this function, the call will fail.

- ***net\_tickintensity =\> NetTickIntensity*:**

  *Net tick intensity*  to use. Defaults to the value of the *net\_tickintensity* *[kernel(7)](/kernel/7.md)* parameter. For more information about *net tick intensity* , see the *kernel* parameter. However, note that if the value of the *kernel* parameter is invalid, it will silently be replaced by a valid value, but if an invalid *NetTickIntensity* value is passed as option value to this function, the call will fail.

- ***dist\_listen =\> boolean()*:**

  Enable or disable listening for incoming connections. Defaults to the value of the *-dist\_listen* *erl* command line argument. Note that *dist\_listen =\> false* implies *hidden =\> true*.

  If *undefined* has been passed as *Name*, the *dist\_listen* option will be overridden with *dist\_listen =\> false*.

- ***hidden =\> boolean()*:**

  Enable or disable hidden node. Defaults to *true* if the *-hidden* *erl* command line argument has been passed; otherwise *false*.

  If *undefined* has been passed as *Name*, or the option *dist\_listen* equals *false*, the *hidden* option will be overridden with *hidden =\> true*.

```
start(Options) -> {ok, pid()} | {error, Reason}
```

Types:

Options = \[Name \| NameDomain \| TickTime, ...\]\
 Name = atom()\
 NameDomain = shortnames \| longnames\
 TickTime = integer() \>= 1\
 Reason = {already\_started, pid()} \| term()\

**Warning:**

*start/1* is deprecated. Use *start/2* instead.

Turns a non-distributed node into a distributed node by starting *net\_kernel* and other necessary processes.

*Options* list can only be exactly one of the following lists (order is imporant):

- ***\[Name\]*:**

  The same as *net\_kernel:start(\[Name, longnames, 15000\])*.

- ***\[Name, NameDomain\]*:**

  The same as *net\_kernel:start(\[Name, NameDomain, 15000\])*.

- ***\[Name, NameDomain, TickTime\]*:**

  The same as *net\_kernel:start(Name, #{name\_domain =\> NameDomain, net\_ticktime =\> ((TickTime\*4-1) div 1000) + 1, net\_tickintensity =\> 4})*. Note that *TickTime* is *not*  the same as net tick time expressed in milliseconds. *TickTime* is the time between ticks when net tick intensity equals *4*.

```
stop() -> ok | {error, Reason}
```

Types:

Reason = not\_allowed \| not\_found\

Turns a distributed node into a non-distributed node. For other nodes in the network, this is the same as the node going down. Only possible when the net kernel was started using *start/2*, otherwise *{error, not\_allowed}* is returned. Returns *{error, not\_found}* if the local node is not alive.
