To receive notifications about scheduled maintenance, please subscribe to the mailing-list gitlab-operations@sympa.ethz.ch. You can subscribe to the mailing-list at https://sympa.ethz.ch

README.md 13.6 KB
Newer Older
cedgar's avatar
readme    
cedgar committed
1
# P4-Utils
cedgar's avatar
test    
cedgar committed
2

cedgar's avatar
cedgar committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
P4-utils is an extension to Mininet that makes P4 networks easier to build, run and debug. P4-utils is strongly
inspired by [p4app](https://github.com/p4lang/p4app).

### Installation

First clone this repository:

```bash
git clone https://github.com/nsg-ethz/p4-utils.git
```

Run the installation script:

```bash
sudo ./install.sh
````

The install script will use `pip -e` to install the project in editable mode, meaning that every time you update the files
in this repository, either by pulling or doing local edits, the changes will automatically take place without the need of
installing the package again.

#### Uninstall

If you want to uninstall run:

```bash
sudo ./uninstall
```

This will remove all the scripts that were added to `/user/bin` as well as uninstall the python package using `pip`.

### How does it work ?

P4-utils creates virtual networks using mininet and extended nodes that run p4-enabled switches. To create hosts,
mininet uses a bash process running in a network namespace, in order words, all the processes that run within the
network namespaces have an isolated network stack. Switches are software-based switches like Open vSwitch, Linux Bridge,
or BMV2 switches. Mininet uses virtual ethernet pairs, which live in the Linux kernel to connect the emulated hosts and switches.

For more information see:

 * [Mininet](http://mininet.org/)
cedgar's avatar
cedgar committed
44
 * [Linux Namespaces](https://blogs.igalia.com/dpino/2016/04/10/network-namespaces/)
cedgar's avatar
cedgar committed
45
46
47
48
49
 * [Virtual ethernet interfaces](http://man7.org/linux/man-pages/man4/veth.4.html)
 * [BMV2](https://github.com/p4lang/behavioral-model), [OVS](https://www.openvswitch.org/), [LinuxBridge](https://cloudbuilder.in/blogs/2013/12/02/linux-bridge-virtual-networking/).

### Features

cedgar's avatar
cedgar committed
50
P4-utils adds on top of minininet:
cedgar's avatar
cedgar committed
51

cedgar's avatar
cedgar committed
52
53
54
55
56
57
58
59
60
 * A command-line launcher (`p4run`) to instantiate networks.
 * A helper script (`mx`) to run processes in namespaces
 * Custom `P4Host` and `P4Switch` nodes (based on the ones provided in the [`p4lang`](https://github.com/p4lang) repo)
 * A very simple way of defining networks using json files (`p4app.json`).
 * Enhances mininet command-line interface: adding the ability of rebooting switches with updated p4 programs and configurations, without the need
 of restarting the entire network.
 * Saves the topology and features in an object that can be loded and queried to extract meaningful information (also build a `networkx` object out of the
 topology)
 * Re-implementation of the `runtime_CLI` and `simple_switch_CLI` as python objects to use in controller code.
Fabian Schleiss's avatar
Fabian Schleiss committed
61

cedgar's avatar
cedgar committed
62
### Usage
Fabian Schleiss's avatar
Fabian Schleiss committed
63

cedgar's avatar
cedgar committed
64
65
P4-utils can be executed by running the `p4run` command in a terminal. By default `p4run` will try to find a
topology description called `p4app.json` in your current path. However you can change that by using the `--config` option:
cedgar's avatar
cedgar committed
66

cedgar's avatar
cedgar committed
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
```bash
p4run --config <path_to_json_configuration>
```

You can see the complete list of options with the `-h` or `--help` options.

## Documentation

### Topology Description

To run any topology p4-utils needs a configuration file (`*.json`) that is used by `p4run` to know how to build and configure a
virtual network. All the possible options are listed below:

#### Global Configuration

cedgar's avatar
cedgar committed
82
83
84
Set of global settings defined in the first layer of the json object that describe the basic
configuration of our topology. For instance the switch type and compiler options can be set here.

cedgar's avatar
cedgar committed
85
86
87
88
89
90
##### `program:`

   * Type: String
   * Value: Path to p4 program
   * Default: None (required if not all switches have a p4 program defined).

cedgar's avatar
cedgar committed
91
   > Program that will be loaded onto all the switches unless a switch you specify a program in the switch conf.
cedgar's avatar
cedgar committed
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

##### `switch:`

   * Type: String
   * Value: path to bmv2 switch executable
   * Default: "simple_switch"

##### `compiler:`

   * Type: String
   * Value: P4 compiler to be used
   * Default: "p4c"

##### `options:`

   * Type: String
   * Value: Compiler options
   * Default: "--target bmv2 --arch v1model --std p4-16"

##### `switch_cli:`

   * Type: String
   * Value: Path to the switch CLI executable
   * Default: 'simple_switch_CLI'

##### `cli:`

   * Type: bool
   * Value: Enables the enhanced mininet CLI. If disabled, the topology will be destroyed right after being created.
   * Default: false

##### `pcap_dump:`

   * Type: bool
   * Value: if enabled a pcap file for each interfaced is saved at `./pcap`
   * Default: false

##### `enable_log:`

   * Type: bool
132
133
134
   * Value: if enabled a directory with CLI and switch logs is created at `.log`. For each switch two files are created, one includes the
   output of the CLI for the entries you populated using the p4-utils library. The second file `<sw_name>.log` includes packet traces that
   show how was the packet processed by the switch pipeline (i.e which branches were executed, table hit/miss, etc).
cedgar's avatar
cedgar committed
135
136
   * Default: false

cedgar's avatar
cedgar committed
137
138
139
140
141
142
143
144
145
146
### Special Modules

During the creation of the network 4 main blocks are used. To make p4utils more modular adding your
own block is allowed.

##### `topo_module`:

Module in charge of building the topology, amongs others it reads the topology object described in
the json configuration file and decides how to configure hosts and switches (i.e Mac and IP address assignment strategy).

cedgar's avatar
cedgar committed
147
##### `controller_module`
cedgar's avatar
cedgar committed
148
149
150
151

The controller module is in charge of configuring switches and populating its tables during
network creation.

cedgar's avatar
cedgar committed
152
##### `topodb_module`
cedgar's avatar
cedgar committed
153
154
155
156

The topologydb module is the object in charge of storing information about the topology and providing and API to extract
useful data.

cedgar's avatar
cedgar committed
157
158
##### `mininnet_module`

cedgar's avatar
cedgar committed
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
Modified version of the Mininet object. It simply adds a new attribute that contains `p4switches`.

**Setting your own module:**

By default each module will use the already defined objects in p4utils. If you want to add your own
implementation you can indicate that in the `json` file using the following syntax:

```javascript
  "topo_module | controller_module | topodb_module | minininet_module>"
  {
    "file_path": "<path to python object>",
    "module_name": "<name of python file>",
    "object_name": "<name of module object>"
  }
```

cedgar's avatar
cedgar committed
175
176
> For modules that are already included in the PYTHONPATH you don't have
to specify the "file_path".
cedgar's avatar
cedgar committed
177

cedgar's avatar
cedgar committed
178
179
#### Topology

cedgar's avatar
cedgar committed
180
181
182
The topology subsection of the configuration describes how the addresses are assigned,
the number of hosts and switches and how are they connected.

cedgar's avatar
cedgar committed
183
##### `assignment_strategy:`
cedgar's avatar
cedgar committed
184

cedgar's avatar
cedgar committed
185
186
187
188
When you use the default `topo_module` you can use different assignment strategies.
Assignment strategies are needed due to the fact that p4-switches can work
at any network layer (L2, L3, ...), and thus there is no way to automatically
configure the hosts, and switches without knowing what will switches do.
cedgar's avatar
cedgar committed
189

cedgar's avatar
cedgar committed
190
191
 * `l2`: all switches in the network are assumed to work at layer 2, thus
 all hosts get assigned to the same subnetwork.
cedgar's avatar
cedgar committed
192

cedgar's avatar
cedgar committed
193
194
195
196
 * `l3`: all switches in the network are assumed to work at layer 3, thus
 all links in the network form a different subnetwork. Hosts can only
 be connected to one switch device which is used to configure the host's gateway.

197
198
199
200
201
 * `mixed`: this is not a real l2 or l3 assignment strategy, but since p4 switches can work at any layer,
 it can be useful for easy prototyping. Hosts connected to the same switch will be assigned an ip within the same subnet. Hosts
 connected to another switch will belong to another subnet. Each hosts can only be connected to a single switch, which at the same time
 is assigned to be the L3 gatway.

cedgar's avatar
cedgar committed
202
203
204
 * `manual`: can be used when your topology will be formed by heterogeneous
 devices, you have to manually set the IP to each interface and host gateways.

cedgar's avatar
cedgar committed
205
 > For more information about assignment strategies see its [doc page](docs/assignment_strategies.md).
cedgar's avatar
cedgar committed
206

cedgar's avatar
cedgar committed
207
208
209
210
211
212
213
214
215
 > By default l2 strategy is used

##### `auto_arp_tables:`

   * Type: bool
   * Value: if set, hosts get their ARP table automatically filled when the network is started. Note: hosts only
   learn the Mac addresses of other hosts within the same subnet.
   * Default: true

cedgar's avatar
cedgar committed
216
217
218
219
220
221
222
##### `auto_gw_arp:`

   * Type: bool
   * Value: if set, hosts get the ARP entry for the gate way route automatically configured. You need to enable this when your gw
   does not reply to ARP requests.
   * Default: true

cedgar's avatar
cedgar committed
223
224
225
226
227
228
229
230
##### `links:`

   * Type: list
   * Value: list of links that connect nodes in the topology.
   * Default: None

   Each link is of the form:
   ```python
meierrol's avatar
meierrol committed
231
   ["node1", "node2", {"delay": <in_ms>, "bw": <in_mbps>, "loss": <in_percent>, "queue_length": <num_packets>, "weight": <link_cost>}]
cedgar's avatar
cedgar committed
232
233
234
235
236
237
238
   ```

   Link characteristics are not mandatory. Also, not all the characteristics have to be defined, you can pick a subset. For the
   characteristics that are not set, the default values are:

   ```python
   link_dict = {'delay': '0ms',
cedgar's avatar
cedgar committed
239
                'bw': Inf,
meierrol's avatar
meierrol committed
240
                'loss': 0,
cedgar's avatar
cedgar committed
241
242
243
                'queue_length': 1000,
                'weight': 1
               }
cedgar's avatar
cedgar committed
244
245
   ```

cedgar's avatar
cedgar committed
246
247
248
   If you want to set the default value for all links, you can set the `default_<attribute>`. You have to set this parammeter at the topology level. Possible, defaults are: 
   `default_delay`, `default_bw`, `default_loss`, `default_queue_length`, `default_link_weight`.

cedgar's avatar
cedgar committed
249
250
251
252
253
##### `hosts:`

   * Type: dict
   * Value: dictionary where the keys are the hosts that have to be created.
   * Default: None
cedgar's avatar
cedgar committed
254
255
256
   * Host Conf Attributes:
       * `ip:` if using manual assignament strategy you can assign an ip to a host or use the keyword `auto` if hosts should be able to get IPs through a DHCP server.
       * `gw:` indicates the IP address of the gateway
257
258
       * `commands:` list of commands that will be executed at starting time. As now, only non blocking commands
        that terminate are allowed here. Example: "commands": ["echo 1 > /etc/config_file"]
cedgar's avatar
cedgar committed
259
260
261
262
263
264
265
266
267
268
269
270

   > TODO: add a way to start commands at hosts: this feature will be added soon.

##### `switches:`


   * Type: dict
   * Value: dictionary where the keys are switch names, and the values are switch confs.
   * Default: None
   * Switch Conf Attributes:
      * `cli_input:` path to the CLI-formatted text file that will be used to configure and populate the switch.
      * `program`: path to the p4 program that will be loaded onto the switch. If not specified, the global `program` path is used.
cedgar's avatar
cedgar committed
271
      * `<direct_neighbor>:` when using the manual IP assignment you can indicate the IP of the interface facing a neighboring node.
cedgar's avatar
cedgar committed
272
273

You can find a configuration example, that uses all the fields [here](./p4app_example.json)
cedgar's avatar
cedgar committed
274

275
276
### Topology Object

cedgar's avatar
fix    
cedgar committed
277
You can use the topology object by simply:
278
279

```python
jurijnota's avatar
jurijnota committed
280
281
from p4utils.utils.helper import load_topo
topo = load_topo('path_to_topology_json')
282

cedgar's avatar
cedgar committed
283
284
# Get all the switches
topo.get_p4switches().keys()
jurijnota's avatar
jurijnota committed
285
['s3', 's2', 's1', 's4']
cedgar's avatar
cedgar committed
286
287

# One node information
jurijnota's avatar
jurijnota committed
288
289
290
291
292
293
topo.get_nodes()['h1']
{"isHost": True, 
"ip": "10.2.1.2/24", 
"mac": "00:00:0a:02:01:02", 
"defaultRoute": "via 10.2.1.1", 
"id": "h1"}
cedgar's avatar
cedgar committed
294
```
295

cedgar's avatar
fix    
cedgar committed
296
297
#### Methods Documentation

cedgar's avatar
cedgar committed
298
299
Some methods documented

cedgar's avatar
cedgar committed
300
301
302
303
* `get_p4switches()`: returns a dictionary where the keys are p4 switches names and values are information about the switch. You can use `get_p4switches().keys()` to
just get the switches names.
* `get_thrift_port(sw_name)`: returns the thrift port at which a `sw_name` is listening to. This can be used to establish a connection using the `SimpleSwitchAPI` object.
* `get_hosts_connected_to(sw_name)`: returns a list of all the host names connected to the switch `sw_name`.
304
* `get_host_ip(host_name)`: returns the ip address and subnet mask of host `host_name`. For example `10.0.1.2/24`.
cedgar's avatar
cedgar committed
305
306
307
308
309
310
* `get_host_mac(host_name)`: returns the mac address of host `host_name`.
* `node_to_node_port_num(node1, node2)`: returns the port index of `node1` facing `node2`. This index can be used to populate your forwarding table entries.
* `node_to_node_mac(node1, node2)`: returns the `mac` address of the interface from `node1` that connects with `node2`. This can be used to get next hop destination mac addresses.
* `get_shortest_paths_between_nodes(node1, node2)`: returns a list of the shortest paths between two nodes. The list includes the src and the destination and multiple equal cost paths
if found. For example, `get_shortest_paths_between_nodes('s1', 's2')` would return `[('s1', 's4', 's2'), ('s1', 's5', 's2')]` if two equal cost paths are found using `s4` and `s5` as next hops.

cedgar's avatar
fix    
cedgar committed
311
* `node_to_node_interface_ip(node1, node2)`: returns the IP address of the interface from `node1` connecting with `node2`. Note that the ip address includes the prefix len at the end `/x`.
cedgar's avatar
cedgar committed
312
313
* `get_interfaces_to_node(sw_name)`: returns a dictionary of all the interfaces as keys and the node they connect to as value. For example `{'s1-eth1': 'h1', 's1-eth2': 's2'}`.
* `interface_to_port(node, intf_name)`: returns the interface index of `intf_name` for `node`.
314

cedgar's avatar
cedgar committed
315
### Control Plane API
cedgar's avatar
cedgar committed
316

cedgar's avatar
cedgar committed
317
318
319
320
The control plane API is a wrapper (with some additions) over the original RuntimeCLI from [p4lang/bmv2](https://github.com/p4lang/behavioral-model/tree/master/tools). It allows
programmers to interface with the bmv2 thrift sever through a python object and by calling methods instead of using text throguh the CLI. Thus, this API allows programmers to write
more automated control plane functions.

cedgar's avatar
cedgar committed
321
While we write a more complete documentation you can check which functions are available to use directly at the source code:
Jurij Nota's avatar
Jurij Nota committed
322
- [SimpleSwitchThriftAPI](p4utils/utils/sswitch_thrift_API.py) and [ThriftAPI](p4utils/utils/thrift_API.py) for thrift switches,
Jurij Nota's avatar
Jurij Nota committed
323
- [SimpleSwitchP4RuntimeAPI](p4utils/utils/sswitch_p4runtime_API.py) for grpc switches.
cedgar's avatar
cedgar committed
324

cedgar's avatar
cedgar committed
325
326
327
328
329
**Note:** Some of the least used functions from the CLI have not been included in this API. However, some extra functions that do not exist in the CLI have
been added here.

**Important:** In the near future, this API should be replaced by the P4Runtime API, however do to lack of implementation for some functions at the time of
implementing this we chose to use the old thrift API.
cedgar's avatar
cedgar committed
330