# ryu.app.rest_vtep

This sample application performs as VTEP for EVPN VXLAN and constructs a Single Subnet per EVI corresponding to the VLAN Based service in [RFC7432].

Note

This app will invoke OVSDB request to the switches. Please set the manager address before calling the API of this app.

    $ sudo ovs-vsctl set-manager ptcp:6640
    $ sudo ovs-vsctl show
        ...(snip)
        Manager "ptcp:6640"
        ...(snip)

## Usage Example

### Environment

This example supposes the following environment:

     Host A (172.17.0.1)                      Host B (172.17.0.2)
    +--------------------+                   +--------------------+
    |   Ryu1             | --- BGP(EVPN) --- |   Ryu2             |
    +--------------------+                   +--------------------+
            |                                       |
    +--------------------+                   +--------------------+
    |   s1 (OVS)         | ===== vxlan ===== |   s2 (OVS)         |
    +--------------------+                   +--------------------+
    (s1-eth1)    (s1-eth2)                   (s2-eth1)    (s2-eth2)
       |            |                           |            |
    +--------+  +--------+                   +--------+  +--------+
    | s1h1   |  | s1h2   |                   | s2h1   |  | s2h2   |
    +--------+  +--------+                   +--------+  +--------+

### Configuration steps

1. Creates a new BGPSpeaker instance on each host.

   > On Host A:

   >     (Host A)$ curl -X POST -d '{
   >      "dpid": 1,
   >      "as_number": 65000,
   >      "router_id": "172.17.0.1"
   >      }' http://localhost:8080/vtep/speakers | python -m json.tool

   > On Host B:

   >     (Host B)$ curl -X POST -d '{
   >      "dpid": 1,
   >      "as_number": 65000,
   >      "router_id": "172.17.0.2"
   >      }' http://localhost:8080/vtep/speakers | python -m json.tool

2. Registers the neighbor for the speakers on each host.

   > On Host A:

   >     (Host A)$ curl -X POST -d '{
   >      "address": "172.17.0.2",
   >      "remote_as": 65000
   >      }' http://localhost:8080/vtep/neighbors |
   >      python -m json.tool

   > On Host B:

   >     (Host B)$ curl -X POST -d '{
   >      "address": "172.17.0.1",
   >      "remote_as": 65000
   >      }' http://localhost:8080/vtep/neighbors |
   >      python -m json.tool

3. Defines a new VXLAN network(VNI=10) on the Host A/B.

   > On Host A:

   >     (Host A)$ curl -X POST -d '{
   >      "vni": 10
   >      }' http://localhost:8080/vtep/networks | python -m json.tool

   > On Host B:

   >     (Host B)$ curl -X POST -d '{
   >      "vni": 10
   >      }' http://localhost:8080/vtep/networks | python -m json.tool

4. Registers the clients to the VXLAN network.

   > For "s1h1"(ip="10.0.0.11", mac="aa:bb:cc:00:00:11") on Host A:

   >     (Host A)$ curl -X POST -d '{
   >      "port": "s1-eth1",
   >      "mac": "aa:bb:cc:00:00:11",
   >      "ip": "10.0.0.11"
   >      } ' http://localhost:8080/vtep/networks/10/clients |
   >      python -m json.tool

   > For "s2h1"(ip="10.0.0.21", mac="aa:bb:cc:00:00:21") on Host B:

   >     (Host B)$ curl -X POST -d '{
   >      "port": "s2-eth1",
   >      "mac": "aa:bb:cc:00:00:21",
   >      "ip": "10.0.0.21"
   >      } ' http://localhost:8080/vtep/networks/10/clients |
   >      python -m json.tool

### Testing

If BGP (EVPN) connection between Ryu1 and Ryu2 has been established, pings between the client s1h1 and s2h1 should work.

    (s1h1)$ ping 10.0.0.21

### Troubleshooting

If connectivity between s1h1 and s2h1 isn't working, please check the followings.

1. Make sure that Host A and Host B have full network connectivity.

   >     (Host A)$ ping 172.17.0.2

2. Make sure that BGP(EVPN) connection has been established.

   >     (Host A)$ curl -X GET http://localhost:8080/vtep/neighbors |
   >      python -m json.tool

   >     ...
   >     {
   >         "172.17.0.2": {
   >             "EvpnNeighbor": {
   >                 "address": "172.17.0.2",
   >                 "remote_as": 65000,
   >                 "state": "up"  # "up" shows the connection established
   >             }
   >         }
   >     }

3. Make sure that BGP(EVPN) routes have been advertised.

   >     (Host A)$ curl -X GET http://localhost:8080/vtep/networks |
   >      python -m json.tool

   >      ...
   >     {
   >         "10": {
   >             "EvpnNetwork": {
   >                 "clients": {
   >                     "aa:bb:cc:00:00:11": {
   >                         "EvpnClient": {
   >                             "ip": "10.0.0.11",
   >                             "mac": "aa:bb:cc:00:00:11",
   >                             "next_hop": "172.17.0.1",
   >                             "port": 1
   >                         }
   >                     },
   >                     "aa:bb:cc:00:00:21": {  # route for "s2h1" on Host B
   >                         "EvpnClient": {
   >                             "ip": "10.0.0.21",
   >                             "mac": "aa:bb:cc:00:00:21",
   >                             "next_hop": "172.17.0.2",
   >                             "port": 3
   >                         }
   >                     }
   >                 },
   >                 "ethernet_tag_id": 0,
   >                 "route_dist": "65000:10",
   >                 "vni": 10
   >             }
   >         }
   >     }

4. Make sure that the IPv6 is enabled on your environment. Some Ryu BGP features require the IPv6 connectivity to bind sockets. Mininet seems to disable IPv6 on its installation.

> For example:

>     $ sysctl net.ipv6.conf.all.disable_ipv6
>     net.ipv6.conf.all.disable_ipv6 = 0  # should NOT be enabled

>     $ grep GRUB_CMDLINE_LINUX_DEFAULT /etc/default/grub
>     # please remove "ipv6.disable=1" and reboot
>     GRUB_CMDLINE_LINUX_DEFAULT="ipv6.disable=1 quiet splash"

5. Make sure that your switch using the OpenFlow version 1.3. This application supports only the OpenFlow version 1.3.

> For example:

>     $ ovs-vsctl get Bridge s1 protocols
>     ["OpenFlow13"]

Note

At the time of this writing, we use the the following version of Ryu, Open vSwitch and Mininet.

    $ ryu --version
    ryu 4.19

    $ ovs-vsctl --version
    ovs-vsctl (Open vSwitch) 2.5.2  # APT packaged version of Ubuntu 16.04
    Compiled Oct 17 2017 16:38:57
    DB Schema 7.12.1

    $ mn --version
    2.2.1  # APT packaged version of Ubuntu 16.04

## REST API

class `ryu.app.rest_vtep.``RestVtepController`(req, link, data, **config)
  `add_speaker`(req, **kwargs)

    Creates a new BGPSpeaker instance.

    Usage:

    > Method | URI
    > --- | ---
    > POST | /vtep/speakers

    Request parameters:

    > Attribute | Description
    > --- | ---
    > dpid | ID of Datapath binding to speaker. (e.g. 1)
    > as_number | AS number. (e.g. 65000)
    > router_id | Router ID. (e.g. "172.17.0.1")

    Example:

        $ curl -X POST -d '{
         "dpid": 1,
         "as_number": 65000,
         "router_id": "172.17.0.1"
         }' http://localhost:8080/vtep/speakers | python -m json.tool

        {
            "172.17.0.1": {
                "EvpnSpeaker": {
                    "as_number": 65000,
                    "dpid": 1,
                    "neighbors": {},
                    "router_id": "172.17.0.1"
                }
            }
        }

  `get_speakers`(_, **kwargs)

    Gets the info of BGPSpeaker instance.

    Usage:

    > Method | URI
    > --- | ---
    > GET | /vtep/speakers

    Example:

        $ curl -X GET http://localhost:8080/vtep/speakers |
         python -m json.tool

        {
            "172.17.0.1": {
                "EvpnSpeaker": {
                    "as_number": 65000,
                    "dpid": 1,
                    "neighbors": {
                        "172.17.0.2": {
                            "EvpnNeighbor": {
                                "address": "172.17.0.2",
                                "remote_as": 65000,
                                "state": "up"
                            }
                        }
                    },
                    "router_id": "172.17.0.1"
                }
            }
        }

  `del_speaker`(_, **kwargs)

    Shutdowns BGPSpeaker instance.

    Usage:

    > Method | URI
    > --- | ---
    > DELETE | /vtep/speakers

    Example:

        $ curl -X DELETE http://localhost:8080/vtep/speakers |
         python -m json.tool

        {
            "172.17.0.1": {
                "EvpnSpeaker": {
                    "as_number": 65000,
                    "dpid": 1,
                    "neighbors": {},
                    "router_id": "172.17.0.1"
                }
            }
        }

  `add_neighbor`(req, **kwargs)

    Registers a new neighbor to the speaker.

    Usage:

    > Method | URI
    > --- | ---
    > POST | /vtep/neighbors

    Request parameters:

    > Attribute | Description
    > --- | ---
    > address | IP address of neighbor. (e.g. "172.17.0.2")
    > remote_as | AS number of neighbor. (e.g. 65000)

    Example:

        $ curl -X POST -d '{
         "address": "172.17.0.2",
         "remote_as": 65000
         }' http://localhost:8080/vtep/neighbors |
         python -m json.tool

        {
            "172.17.0.2": {
                "EvpnNeighbor": {
                    "address": "172.17.0.2",
                    "remote_as": 65000,
                    "state": "down"
                }
            }
        }

  `get_neighbors`(_, **kwargs)

    Gets a list of all neighbors.

    Usage:

    > Method | URI
    > --- | ---
    > GET | /vtep/neighbors

    Example:

        $ curl -X GET http://localhost:8080/vtep/neighbors |
         python -m json.tool

        {
            "172.17.0.2": {
                "EvpnNeighbor": {
                    "address": "172.17.0.2",
                    "remote_as": 65000,
                    "state": "up"
                }
            }
        }

  `get_neighbor`(_, **kwargs)

    Gets the neighbor for the specified address.

    Usage:

    > Method | URI
    > --- | ---
    > GET | /vtep/neighbors/{address}

    Request parameters:

    > Attribute | Description
    > --- | ---
    > address | IP address of neighbor. (e.g. "172.17.0.2")

    Example:

        $ curl -X GET http://localhost:8080/vtep/neighbors/172.17.0.2 |
         python -m json.tool

        {
            "172.17.0.2": {
                "EvpnNeighbor": {
                    "address": "172.17.0.2",
                    "remote_as": 65000,
                    "state": "up"
                }
            }
        }

  `del_neighbor`(_, **kwargs)

    Unregister the specified neighbor from the speaker.

    Usage:

    > Method | URI
    > --- | ---
    > DELETE | /vtep/speaker/neighbors/{address}

    Request parameters:

    > Attribute | Description
    > --- | ---
    > address | IP address of neighbor. (e.g. "172.17.0.2")

    Example:

        $ curl -X DELETE http://localhost:8080/vtep/speaker/neighbors/172.17.0.2 |
         python -m json.tool

        {
            "172.17.0.2": {
                "EvpnNeighbor": {
                    "address": "172.17.0.2",
                    "remote_as": 65000,
                    "state": "up"
                }
            }
        }

  `add_network`(req, **kwargs)

    Defines a new network.

    Usage:

    > Method | URI
    > --- | ---
    > POST | /vtep/networks

    Request parameters:

    > Attribute | Description
    > --- | ---
    > vni | Virtual Network Identifier. (e.g. 10)

    Example:

        $ curl -X POST -d '{
         "vni": 10
         }' http://localhost:8080/vtep/networks | python -m json.tool

        {
            "10": {
                "EvpnNetwork": {
                    "clients": {},
                    "ethernet_tag_id": 0,
                    "route_dist": "65000:10",
                    "vni": 10
                }
            }
        }

  `get_networks`(_, **kwargs)

    Gets a list of all networks.

    Usage:

    > Method | URI
    > --- | ---
    > GET | /vtep/networks

    Example:

        $ curl -X GET http://localhost:8080/vtep/networks |
         python -m json.tool

        {
            "10": {
                "EvpnNetwork": {
                    "clients": {
                        "aa:bb:cc:dd:ee:ff": {
                            "EvpnClient": {
                                "ip": "10.0.0.1",
                                "mac": "aa:bb:cc:dd:ee:ff",
                                "next_hop": "172.17.0.1",
                                "port": 1
                            }
                        }
                    },
                    "ethernet_tag_id": 0,
                    "route_dist": "65000:10",
                    "vni": 10
                }
            }
        }

  `get_network`(_, **kwargs)

    Gets the network for the specified VNI.

    Usage:

    > Method | URI
    > --- | ---
    > GET | /vtep/networks/{vni}

    Request parameters:

    > Attribute | Description
    > --- | ---
    > vni | Virtual Network Identifier. (e.g. 10)

    Example:

        $ curl -X GET http://localhost:8080/vtep/networks/10 |
         python -m json.tool

        {
            "10": {
                "EvpnNetwork": {
                    "clients": {
                        "aa:bb:cc:dd:ee:ff": {
                            "EvpnClient": {
                                "ip": "10.0.0.1",
                                "mac": "aa:bb:cc:dd:ee:ff",
                                "next_hop": "172.17.0.1",
                                "port": 1
                            }
                        }
                    },
                    "ethernet_tag_id": 0,
                    "route_dist": "65000:10",
                    "vni": 10
                }
            }
        }

  `del_network`(_, **kwargs)

    Deletes the network for the specified VNI.

    Usage:

    > Method | URI
    > --- | ---
    > DELETE | /vtep/networks/{vni}

    Request parameters:

    > Attribute | Description
    > --- | ---
    > vni | Virtual Network Identifier. (e.g. 10)

    Example:

        $ curl -X DELETE http://localhost:8080/vtep/networks/10 |
         python -m json.tool

        {
            "10": {
                "EvpnNetwork": {
                    "ethernet_tag_id": 10,
                    "clients": [
                        {
                            "EvpnClient": {
                                "ip": "10.0.0.11",
                                "mac": "e2:b1:0c:ba:42:ed",
                                "port": 1
                            }
                        }
                    ],
                    "route_dist": "65000:100",
                    "vni": 10
                }
            }
        }

  `add_client`(req, **kwargs)

    Registers a new client to the specified network.

    Usage:

    > Method | URI
    > --- | ---
    > POST | /vtep/networks/{vni}/clients

    Request parameters:

    > Attribute | Description
    > --- | ---
    > vni | Virtual Network Identifier. (e.g. 10)
    > port | Port number to connect client. For convenience, port name can be specified and automatically translated to port number. (e.g. "s1-eth1" or 1)
    > mac | Client MAC address to register. (e.g. "aa:bb:cc:dd:ee:ff")
    > ip | Client IP address. (e.g. "10.0.0.1")

    Example:

        $ curl -X POST -d '{
         "port": "s1-eth1",
         "mac": "aa:bb:cc:dd:ee:ff",
         "ip": "10.0.0.1"
         }' http://localhost:8080/vtep/networks/10/clients |
         python -m json.tool

        {
            "10": {
                "EvpnClient": {
                    "ip": "10.0.0.1",
                    "mac": "aa:bb:cc:dd:ee:ff",
                    "next_hop": "172.17.0.1",
                    "port": 1
                }
            }
        }

  `del_client`(_, **kwargs)

    Registers a new client to the specified network.

    Usage:

    > Method | URI
    > --- | ---
    > DELETE | /vtep/networks/{vni}/clients/{mac}

    Request parameters:

    > Attribute | Description
    > --- | ---
    > vni | Virtual Network Identifier. (e.g. 10)
    > mac | Client MAC address to register.

    Example:

        $ curl -X DELETE http://localhost:8080/vtep/networks/10/clients/aa:bb:cc:dd:ee:ff |
         python -m json.tool

        {
            "10": {
                "EvpnClient": {
                    "ip": "10.0.0.1",
                    "mac": "aa:bb:cc:dd:ee:ff",
                    "next_hop": "172.17.0.1",
                    "port": 1
                }
            }
        }