First of all: thanks for your interest in my OpenVPN driver. I will be on vacation for the next two weeks, but after that I'll try to join the IRC meetings. Just to clarify: the hook-scripts run on the server's side, and are triggered when a client connects to openvpn: - I use an authentication hook to verify the client's username and password against Keystone (if the client can get a Keystone token, then he's allowed to login to the VPN). This I actually do via the Keystone client API, and it doesn't need any interaction with Neutron or the Neutron agent. - After the client has connected successfully, there's another hook, giving me the client's mac address. I think that the "registration" of the client in Neutron (create a Port, assign an IP address, ...) should be done by the Neutron agent (instead of the procedure I described in #6). Can you recommend a way for the hook script to signal events to the agent (I guess I could use a local socket, or monitor a file...)? Re the vpnservice object: I'm using the router_id in the same way the IPSEC VPN does (I think). I start an openvpn process in the router's network namespace, and have it listen on vpnservice.external_ip (the qg-* device). From what I can tell, there is nothing special in describing an L2-based VPN, and so far I didn't feel a need to change APIs. The difference comes when clients connect. Then instead of connecting networks via routing, I bring clients directly into the Neutron network by bridging OpenVPN's tap device with the qr-* port of the router. I'm not making any changes to routing/iptables. The result is then: $ ip netns exec qrouter-f4d3c149-f85a-4530-98f1-2efdbb151787 ip -4 l 1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: tap0: mtu 1500 qdisc pfifo_fast master qr-br-cf47a7c9 state UP mode DEFAULT group default qlen 100 link/ether 42:66:e6:18:a0:7a brd ff:ff:ff:ff:ff:ff 3: qr-br-cf47a7c9: mtu 1450 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether 42:66:e6:18:a0:7a brd ff:ff:ff:ff:ff:ff 18: qr-cf47a7c9-dc: mtu 1450 qdisc noqueue master qr-br-cf47a7c9 state UNKNOWN mode DEFAULT group default qlen 1000 link/ether fa:16:3e:4c:82:21 brd ff:ff:ff:ff:ff:ff 19: qg-7342ede0-d1: mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/ether fa:16:3e:39:b8:67 brd ff:ff:ff:ff:ff:ff $ ip netns exec qrouter-f4d3c149-f85a-4530-98f1-2efdbb151787 ip -4 a 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 3: qr-br-cf47a7c9: mtu 1450 qdisc noqueue state UP group default qlen 1000 inet 192.168.252.1/24 brd 192.168.252.255 scope global qr-br-cf47a7c9 valid_lft forever preferred_lft forever 19: qg-7342ede0-d1: mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000 inet 10.10.20.113/24 brd 10.10.20.255 scope global qg-7342ede0-d1 valid_lft forever preferred_lft forever $ ip netns exec qrouter-f4d3c149-f85a-4530-98f1-2efdbb151787 brctl show bridge name bridge id STP enabled interfaces qr-br-cf47a7c9 8000.4266e618a07a no qr-cf47a7c9-dc tap0