Acked-by: Ariel Tubaltsev <atubalt...@vmware.com>


On 9/19/14 7:29 AM, "Gurucharan Shetty" <shet...@nicira.com> wrote:

>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 <gshe...@nicira.com>
>---
> vtep/ovs-vtep |  178
>++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 176 insertions(+), 2 deletions(-)
>
>diff --git a/vtep/ovs-vtep b/vtep/ovs-vtep
>index 0b855bb..7173644 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)
>-- 
>1.7.9.5
>
>_______________________________________________
>dev mailing list
>dev@openvswitch.org
>https://urldefense.proofpoint.com/v1/url?u=http://openvswitch.org/mailman/
>listinfo/dev&k=oIvRg1%2BdGAgOoM1BIlLLqw%3D%3D%0A&r=MV0ainYANUJshevWnic4Bqj
>PTBitdF4sSVi8%2ByXyTlU%3D%0A&m=ZoKgFkL8vSR0o1A1Z89Khkjc0cJxUggwm%2FOq7jH9l
>18%3D%0A&s=5619125a8f84a3073e4556be4582eb3b150be5b69e6c7f3c6c06355f96f4053
>d

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to