summaryrefslogtreecommitdiff
path: root/vtep
diff options
context:
space:
mode:
authorGurucharan Shetty <gshetty@nicira.com>2014-07-30 09:11:43 -0700
committerGurucharan Shetty <gshetty@nicira.com>2014-10-13 14:35:34 -0700
commit919026381debc9c0f97a238ef23c2a952dc84216 (patch)
tree00e1e4909d4f5301142214196abaf3e0423b3e0d /vtep
parent2aca2188999d8986b664d4813b88c5c5823dc977 (diff)
downloadopenvswitch-919026381debc9c0f97a238ef23c2a952dc84216.tar.gz
ovs-vtep: Add support for bfd tunnels.
The VTEP emulator creates one OVS bridge for every logical switch and then programs flow in it based on learned local macs and controller programmed remote macs. Multiple logical switches can have multiple OVS tunnels to the same remote machine (with different tunnel ids). But VTEP schema expects a single BFD session between two physical locators. Therefore create a separate bridge ('bfd_bridge') and create a single OVS tunnel between two physical locators (using reference counter). The creation of BFD tunnels by the VTEP emulator is mostly for reporting purposes. That is, it can be used by the controller to figure out that a remote port is down. The emulator itself does not base any of its forwarding decisions based on the state of a bfd tunnel. Signed-off-by: Gurucharan Shetty <gshetty@nicira.com> Acked-by: Ariel Tubaltsev <atubaltsev@vmware.com>
Diffstat (limited to 'vtep')
-rwxr-xr-xvtep/ovs-vtep178
1 files changed, 176 insertions, 2 deletions
diff --git a/vtep/ovs-vtep b/vtep/ovs-vtep
index 0b855bbd2..717364464 100755
--- a/vtep/ovs-vtep
+++ b/vtep/ovs-vtep
@@ -45,6 +45,8 @@ Lswitches = {}
Bindings = {}
ls_count = 0
tun_id = 0
+bfd_bridge = "vtep_bfd"
+bfd_ref = {}
def call_prog(prog, args_list):
cmd = [prog, "-vconsole:off"] + args_list
@@ -113,6 +115,10 @@ class Logical_Switch(object):
ovs_ofctl("del-flows %s" % self.short_name)
ovs_ofctl("add-flow %s priority=0,action=drop" % self.short_name)
+ def cleanup_ls(self):
+ for port_no, tun_name, remote_ip in self.tunnels.itervalues():
+ del_bfd(remote_ip)
+
def update_flood(self):
flood_ports = self.ports.values()
@@ -181,7 +187,9 @@ class Logical_Switch(object):
# Give the system a moment to allocate the port number
time.sleep(0.5)
- self.tunnels[tunnel] = (port_no, tun_name)
+ self.tunnels[tunnel] = (port_no, tun_name, ip)
+
+ add_bfd(ip)
ovs_ofctl("add-flow %s table=0,priority=1000,in_port=%s,"
"actions=resubmit(,1)"
@@ -190,11 +198,13 @@ class Logical_Switch(object):
def del_tunnel(self, tunnel):
vlog.info("removing tunnel %s" % tunnel)
- port_no, tun_name = self.tunnels[tunnel]
+ port_no, tun_name, remote_ip = self.tunnels[tunnel]
ovs_ofctl("del-flows %s table=0,in_port=%s"
% (self.short_name, port_no))
ovs_vsctl("del-port %s %s" % (self.short_name, tun_name))
+ del_bfd(remote_ip)
+
del self.tunnels[tunnel]
def update_local_macs(self):
@@ -309,6 +319,156 @@ class Logical_Switch(object):
self.update_remote_macs()
self.update_stats()
+def get_vtep_tunnel(remote_ip):
+ # Get the physical_locator record for the local tunnel end point.
+ column = vtep_ctl("--columns=_uuid find physical_locator "
+ "dst_ip=%s" % Tunnel_Ip)
+ local = column.partition(":")[2].strip()
+ if not local:
+ return (None, None, None)
+
+ # Get the physical_locator record for the remote tunnel end point.
+ column = vtep_ctl("--columns=_uuid find physical_locator "
+ "dst_ip=%s" % remote_ip)
+ remote = column.partition(":")[2].strip()
+ if not remote:
+ return (None, None, None)
+
+ column = vtep_ctl("--columns=_uuid find tunnel "
+ "local=%s remote=%s" % (local, remote))
+ tunnel = column.partition(":")[2].strip()
+
+ return (local, remote, tunnel)
+
+def create_vtep_tunnel(remote_ip):
+ local, remote, tunnel = get_vtep_tunnel(remote_ip)
+ if not local or not remote:
+ return None
+
+ if not tunnel:
+ vlog.info("creating tunnel record in vtep for remote_ip:%s"
+ % remote_ip)
+ tunnel = vtep_ctl("add physical_switch %s tunnels @tun -- "
+ "--id=@tun create Tunnel local=%s remote=%s"
+ %(ps_name, local, remote))
+ return tunnel
+
+def destroy_vtep_tunnel(remote_ip):
+ local, remote, tunnel = get_vtep_tunnel(remote_ip)
+ if tunnel:
+ vlog.info("destroying tunnel record in vtep for remote_ip:%s"
+ % remote_ip)
+ vtep_ctl("remove physical_switch %s tunnels %s "
+ "-- --if-exists destroy tunnel %s"
+ % (ps_name, tunnel, tunnel))
+
+def add_bfd(remote_ip):
+ # The VTEP emulator creates one OVS bridge for every logical switch.
+ # Multiple logical switches can have multiple OVS tunnels to the
+ # same machine (with different tunnel ids). But VTEP schema expects
+ # a single BFD session between two physical locators. Therefore
+ # create a separate bridge ('bfd_bridge') and create a single OVS tunnel
+ # between two phsyical locators (using reference counter).
+ if remote_ip in bfd_ref:
+ bfd_ref[remote_ip] += 1
+ return
+
+ vlog.info("adding bfd tunnel for remote_ip:%s" % remote_ip)
+
+ port_name = "bfd" + remote_ip
+ # Don't enable BFD yet. Enabling or disabling BFD is based on
+ # the controller setting a value in VTEP DB's tunnel record.
+ ovs_vsctl("--may-exist add-port %s %s "
+ " -- set Interface %s type=vxlan options:remote_ip=%s"
+ % (bfd_bridge, port_name, port_name, remote_ip))
+ bfd_ref[remote_ip] = 1
+
+ # Ideally, we should create a 'tunnel' record in the VTEP DB here.
+ # To create a 'tunnel' record, we need 2 entries in 'physical_locator'
+ # table (one for local and one for remote). But, 'physical_locator'
+ # can be created/destroyed asynchronously when the remote controller
+ # adds/removes entries in Ucast_Macs_Remote table. To prevent race
+ # conditions, pass the responsibility of creating a 'tunnel' record
+ # to run_bfd() which runs more often.
+
+def del_bfd(remote_ip):
+ if remote_ip in bfd_ref:
+ if bfd_ref[remote_ip] == 1:
+ port_name = "bfd" + remote_ip
+ vlog.info("deleting bfd tunnel for remote_ip:%s" % remote_ip)
+ ovs_vsctl("--if-exists del-port %s" % port_name)
+ destroy_vtep_tunnel(remote_ip)
+ del bfd_ref[remote_ip]
+ else:
+ bfd_ref[remote_ip] -= 1
+
+def run_bfd():
+ bfd_ports = ovs_vsctl("list-ports %s" % bfd_bridge).split()
+ for port in bfd_ports:
+ remote_ip = ovs_vsctl("get interface %s options:remote_ip" % port)
+ tunnel = create_vtep_tunnel(remote_ip)
+ if not tunnel:
+ continue
+
+ bfd_params_default = {'bfd_params:enable' : 'false',
+ 'bfd_params:min_rx' : 1000,
+ 'bfd_params:min_tx' : 100,
+ 'bfd_params:decay_min_rx' : 0,
+ 'bfd_params:cpath_down' : 'false',
+ 'bfd_params:check_tnl_key' : 'false'}
+ bfd_params_values = {}
+
+ for key, default in bfd_params_default.iteritems():
+ column = vtep_ctl("--if-exists get tunnel %s %s"
+ % (tunnel, key))
+ if not column:
+ bfd_params_values[key] = default
+ else:
+ bfd_params_values[key] = column
+
+ for key, value in bfd_params_values.iteritems():
+ new_key = key.replace('_params','')
+ ovs_vsctl("set interface %s %s=%s" % (port, new_key, value))
+
+ bfd_status = ['bfd_status:state', 'bfd_status:forwarding',
+ 'bfd_status:diagnostic', 'bfd_status:remote_state',
+ 'bfd_status:remote_diagnostic']
+ for key in bfd_status:
+ value = ovs_vsctl("--if-exists get interface %s %s" % (port, key))
+ if value:
+ vtep_ctl("set tunnel %s %s=%s" %(tunnel, key, value))
+ else:
+ new_key = key.replace('bfd_status:', '')
+ vtep_ctl("remove tunnel %s bfd_status %s" % (tunnel, new_key))
+
+ vtep_ctl("set tunnel %s bfd_status:enabled=%s"
+ % (tunnel, bfd_params_values['bfd_params:enable']))
+
+ # Add the defaults as described in VTEP schema to make it explicit.
+ bfd_lconf_default = {'bfd_config_local:bfd_dst_ip' : '169.254.1.0',
+ 'bfd_config_local:bfd_dst_mac' :
+ '00:23:20:00:00:01'}
+ for key, value in bfd_lconf_default.iteritems():
+ vtep_ctl("set tunnel %s %s=%s" %(tunnel, key, value))
+
+ # bfd_config_remote options from VTEP DB should be populated to
+ # corresponding OVS DB values.
+ bfd_dst_ip = vtep_ctl("--if-exists get tunnel %s "
+ "bfd_config_remote:bfd_dst_ip" % (tunnel))
+ if not bfd_dst_ip:
+ bfd_dst_ip = "169.254.1.1"
+
+ bfd_dst_mac = vtep_ctl("--if-exists get tunnel %s "
+ "bfd_config_remote:bfd_dst_mac" % (tunnel))
+ if not bfd_dst_mac:
+ bfd_dst_mac = "00:23:20:00:00:01"
+
+ ovs_vsctl("set interface %s bfd:bfd_dst_ip=%s "
+ "bfd:bfd_remote_dst_mac=%s bfd:bfd_local_dst_mac=%s"
+ % (port, bfd_dst_ip,
+ bfd_lconf_default['bfd_config_local:bfd_dst_mac'],
+ bfd_dst_mac))
+
def add_binding(binding, ls):
vlog.info("adding binding %s" % binding)
@@ -425,6 +585,7 @@ def handle_physical():
del_binding(binding, ls)
if not len(ls.ports):
+ ls.cleanup_ls()
ovs_vsctl("del-br %s" % Lswitches[ls_name].short_name)
vtep_ctl("clear-local-macs %s" % Lswitches[ls_name].name)
del Lswitches[ls_name]
@@ -466,6 +627,17 @@ def setup():
ovs_vsctl("del-br %s" % br)
+ if br == bfd_bridge:
+ bfd_ports = ovs_vsctl("list-ports %s" % bfd_bridge).split()
+ for port in bfd_ports:
+ remote_ip = ovs_vsctl("get interface %s options:remote_ip"
+ % port)
+ tunnel = destroy_vtep_tunnel(remote_ip)
+
+ ovs_vsctl("del-br %s" % br)
+
+ ovs_vsctl("add-br %s" % bfd_bridge)
+
def main():
parser = argparse.ArgumentParser()
@@ -510,6 +682,8 @@ def main():
for ls_name, ls in Lswitches.items():
ls.run()
+ run_bfd()
+
poller = ovs.poller.Poller()
unixctl.wait(poller)
poller.timer_wait(1000)