]> git.proxmox.com Git - ovs.git/blobdiff - vtep/ovs-vtep
treewide: Fix recent flake8-check.
[ovs.git] / vtep / ovs-vtep
index eb8e97b1fc7fb16b7399932ff27575dff92cba24..9a5aa3d680bb25ec2f48692ebbd41e22096561d0 100755 (executable)
@@ -22,13 +22,14 @@ import shlex
 import subprocess
 import sys
 import time
-import types
 
 import ovs.dirs
 import ovs.util
 import ovs.daemon
 import ovs.unixctl.server
 import ovs.vlog
+from six.moves import range
+import six
 
 
 VERSION = "0.99"
@@ -56,7 +57,7 @@ def call_prog(prog, args_list):
     if len(output) == 0 or output[0] is None:
         output = ""
     else:
-        output = output[0].strip()
+        output = output[0].decode().strip()
     return output
 
 
@@ -79,34 +80,24 @@ def unixctl_exit(conn, unused_argv, unused_aux):
 
 
 class Logical_Switch(object):
-    def __init__(self, ls_name):
+    def __init__(self, ls_name, ps_name):
         global ls_count
         self.name = ls_name
         ls_count += 1
-        self.short_name = "vtep_ls" + str(ls_count)
+        self.short_name = ps_name + "_vtep_ls" + str(ls_count)
         vlog.info("creating lswitch %s (%s)" % (self.name, self.short_name))
         self.ports = {}
         self.tunnels = {}
         self.local_macs = set()
         self.remote_macs = {}
         self.unknown_dsts = set()
-        self.tunnel_key = 0
         self.setup_ls()
+        self.replication_mode = "service_node"
 
     def __del__(self):
         vlog.info("destroying lswitch %s" % self.name)
 
     def setup_ls(self):
-        column = vtep_ctl("--columns=tunnel_key find logical_switch "
-                              "name=%s" % self.name)
-        tunnel_key = column.partition(":")[2].strip()
-        if tunnel_key and isinstance(eval(tunnel_key), types.IntType):
-            self.tunnel_key = tunnel_key
-            vlog.info("using tunnel key %s in %s"
-                      % (self.tunnel_key, self.name))
-        else:
-            self.tunnel_key = 0
-            vlog.warn("invalid tunnel key for %s, using 0" % self.name)
 
         if ps_type:
             ovs_vsctl("--may-exist add-br %s -- set Bridge %s datapath_type=%s"
@@ -126,26 +117,30 @@ class Logical_Switch(object):
         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():
+        for port_no, tun_name, remote_ip in six.itervalues(self.tunnels):
             del_bfd(remote_ip)
 
     def update_flood(self):
-        flood_ports = self.ports.values()
+        flood_ports = list(self.ports.values())
 
         # Traffic flowing from one 'unknown-dst' should not be flooded to
         # port belonging to another 'unknown-dst'.
         for tunnel in self.unknown_dsts:
             port_no = self.tunnels[tunnel][0]
             ovs_ofctl("add-flow %s table=1,priority=1,in_port=%s,action=%s"
-                        % (self.short_name, port_no, ",".join(flood_ports)))
-
-        # Traffic coming from a VTEP physical port should only be flooded to
-        # one 'unknown-dst' and to all other physical ports that belong to that
-        # VTEP device and this logical switch.
+                      % (self.short_name, port_no, ",".join(flood_ports)))
+
+        # Traffic coming from a VTEP physical port should always be flooded to
+        # all the other physical ports that belong to that VTEP device and
+        # this logical switch.  If the replication mode is service node then
+        # send to one unknown_dst node (the first one here); else we assume the
+        # replication mode is source node and we send the packet to all
+        # unknown_dst nodes.
         for tunnel in self.unknown_dsts:
             port_no = self.tunnels[tunnel][0]
             flood_ports.append(port_no)
-            break
+            if self.replication_mode == "service_node":
+                break
 
         ovs_ofctl("add-flow %s table=1,priority=0,action=%s"
                   % (self.short_name, ",".join(flood_ports)))
@@ -165,11 +160,11 @@ class Logical_Switch(object):
     def del_lbinding(self, lbinding):
         vlog.info("removing %s binding from %s" % (lbinding, self.name))
         port_no = self.ports[lbinding]
-        ovs_ofctl("del-flows %s in_port=%s" % (self.short_name, port_no));
+        ovs_ofctl("del-flows %s in_port=%s" % (self.short_name, port_no))
         del self.ports[lbinding]
         self.update_flood()
 
-    def add_tunnel(self, tunnel):
+    def add_tunnel(self, tunnel, tunnel_key):
         global tun_id
         vlog.info("adding tunnel %s" % tunnel)
         encap, ip = tunnel.split("/")
@@ -183,7 +178,7 @@ class Logical_Switch(object):
 
         ovs_vsctl("add-port %s %s -- set Interface %s type=vxlan "
                   "options:key=%s options:remote_ip=%s"
-                  % (self.short_name, tun_name, tun_name, self.tunnel_key, ip))
+                  % (self.short_name, tun_name, tun_name, tunnel_key, ip))
 
         for i in range(10):
             port_no = ovs_vsctl("get Interface %s ofport" % tun_name)
@@ -210,7 +205,7 @@ class Logical_Switch(object):
 
         port_no, tun_name, remote_ip = self.tunnels[tunnel]
         ovs_ofctl("del-flows %s table=0,in_port=%s"
-                    % (self.short_name, port_no))
+                  % (self.short_name, port_no))
         ovs_vsctl("del-port %s %s" % (self.short_name, tun_name))
 
         del_bfd(remote_ip)
@@ -253,6 +248,17 @@ class Logical_Switch(object):
         tunnels = set()
         parse_ucast = True
 
+        column = vtep_ctl("--columns=tunnel_key find logical_switch "
+                          "name=%s" % self.name)
+        tunnel_key = column.partition(":")[2].strip()
+        if tunnel_key and isinstance(eval(tunnel_key), six.integer_types):
+            vlog.info("update_remote_macs: using tunnel key %s in %s"
+                      % (tunnel_key, self.name))
+        else:
+            vlog.info("Invalid tunnel key %s in %s post VTEP DB requery"
+                      % (tunnel_key, self.name))
+            return
+
         mac_list = vtep_ctl("list-remote-macs %s" % self.name).splitlines()
         for line in mac_list:
             if (line.find("mcast-mac-remote") != -1):
@@ -276,23 +282,45 @@ class Logical_Switch(object):
         old_tunnels = set(self.tunnels.keys())
 
         for tunnel in tunnels.difference(old_tunnels):
-            self.add_tunnel(tunnel)
+            self.add_tunnel(tunnel, tunnel_key)
 
         for tunnel in old_tunnels.difference(tunnels):
             self.del_tunnel(tunnel)
 
-        for mac in remote_macs.keys():
+        for mac in six.iterkeys(remote_macs):
             if (self.remote_macs.get(mac) != remote_macs[mac]):
                 self.add_remote_mac(mac, remote_macs[mac])
 
-        for mac in self.remote_macs.keys():
-            if not remote_macs.has_key(mac):
+        for mac in six.iterkeys(self.remote_macs):
+            if mac not in remote_macs:
                 self.del_remote_mac(mac)
 
         self.remote_macs = remote_macs
 
+        replication_mode = vtep_ctl("get logical_switch %s replication_mode"
+                                    % self.name)
+
+        # Replication mode is an optional column and if it is not set,
+        # replication mode defaults to service_node.
+        if replication_mode == "[]":
+            replication_mode = "service_node"
+
+        # If the logical switch level replication mode has changed then
+        # update to that value.
+        update_flood_set = False
+        if replication_mode != self.replication_mode:
+            self.replication_mode = replication_mode
+            vlog.info("%s replication mode changed to %s" %
+                      (self.name, self.replication_mode))
+            update_flood_set = True
+
         if (self.unknown_dsts != unknown_dsts):
             self.unknown_dsts = unknown_dsts
+            update_flood_set = True
+
+        # If either the replication mode has changed or the unknown
+        # destinations set has changed, update the flooding decision.
+        if update_flood_set is True:
             self.update_flood()
 
     def update_stats(self):
@@ -307,7 +335,7 @@ class Logical_Switch(object):
 
         # Go through all the logical switch's interfaces that end with "-l"
         # and copy the statistics to logical_binding_stats.
-        for interface in self.ports.iterkeys():
+        for interface in six.iterkeys(self.ports):
             if not interface.endswith("-l"):
                 continue
             # Physical ports can have a '-' as part of its name.
@@ -318,11 +346,11 @@ class Logical_Switch(object):
             if not uuid:
                 continue
 
-            for (mapfrom, mapto) in stats_map.iteritems():
+            for mapfrom, mapto in six.iteritems(stats_map):
                 value = ovs_vsctl("get interface %s statistics:%s"
-                                % (interface, mapfrom)).strip('"')
+                                  % (interface, mapfrom)).strip('"')
                 vtep_ctl("set logical_binding_stats %s %s=%s"
-                        % (uuid, mapto, value))
+                         % (uuid, mapto, value))
 
     def run(self):
         self.update_local_macs()
@@ -434,15 +462,15 @@ def run_bfd():
                               'bfd_params:check_tnl_key': 'false'}
         bfd_params_values = {}
 
-        for key, default in bfd_params_default.iteritems():
+        for key, default in six.iteritems(bfd_params_default):
             column = vtep_ctl("--if-exists get tunnel %s %s"
-                               % (tunnel, key))
+                              % (tunnel, key))
             if not column:
                 bfd_params_values[key] = default
             else:
                 bfd_params_values[key] = column
 
-        for key, value in bfd_params_values.iteritems():
+        for key, value in six.iteritems(bfd_params_values):
             new_key = key.replace('_params', '')
             ovs_vsctl("set interface %s %s=%s" % (port, new_key, value))
 
@@ -463,8 +491,8 @@ def run_bfd():
         # 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():
+                             '00:23:20:00:00:01'}
+        for key, value in six.iteritems(bfd_lconf_default):
             vtep_ctl("set tunnel %s %s=%s" % (tunnel, key, value))
 
         # bfd_config_remote options from VTEP DB should be populated to
@@ -475,15 +503,15 @@ def run_bfd():
             bfd_dst_ip = "169.254.1.1"
 
         bfd_dst_mac = vtep_ctl("--if-exists get tunnel %s "
-                              "bfd_config_remote:bfd_dst_mac" % (tunnel))
+                               "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))
+                     bfd_lconf_default['bfd_config_local:bfd_dst_mac'],
+                     bfd_dst_mac))
 
 
 def add_binding(binding, ls):
@@ -520,9 +548,9 @@ def add_binding(binding, ls):
     # Create a logical_bindings_stats record.
     if not vlan_:
         vlan_ = "0"
-    vtep_ctl("set physical_port %s vlan_stats:%s=@stats --\
-            --id=@stats create logical_binding_stats packets_from_local=0"\
-            % (pp_name, vlan_))
+    vtep_ctl("set physical_port %s vlan_stats:%s=@stats -- "
+             "--id=@stats create logical_binding_stats packets_from_local=0"
+             % (pp_name, vlan_))
 
     ls.add_lbinding(lbinding)
     Bindings[binding] = ls.name
@@ -543,8 +571,8 @@ def del_binding(binding, ls):
                   % (ps_name, port_no, vlan_))
         ovs_ofctl("del-flows %s in_port=%s" % (ps_name, patch_no))
     else:
-        ovs_ofctl("del-flows %s in_port=%s" % (ps_name, port_no))
-        ovs_ofctl("del-flows %s in_port=%s" % (ps_name, patch_no))
+        ovs_ofctl("--strict del-flows %s in_port=%s" % (ps_name, port_no))
+        ovs_ofctl("--strict del-flows %s in_port=%s" % (ps_name, patch_no))
 
     ls.del_lbinding(lbinding)
 
@@ -581,13 +609,13 @@ def handle_physical():
         for b in binding_set:
             vlan, ls_name = b.split()
             if ls_name not in Lswitches:
-                Lswitches[ls_name] = Logical_Switch(ls_name)
+                Lswitches[ls_name] = Logical_Switch(ls_name, ps_name)
 
             binding = "%s-%s" % (vlan, pp_name)
             ls = Lswitches[ls_name]
             new_bindings.add(binding)
 
-            if Bindings.has_key(binding):
+            if binding in Bindings:
                 if Bindings[binding] == ls_name:
                     continue
                 else:
@@ -712,7 +740,7 @@ def main():
 
         handle_physical()
 
-        for ls_name, ls in Lswitches.items():
+        for ls_name, ls in six.iteritems(Lswitches):
             ls.run()
 
         run_bfd()
@@ -724,6 +752,7 @@ def main():
 
     unixctl.close()
 
+
 if __name__ == '__main__':
     try:
         main()