Example #1
0
 def _manage_ports(self):
     try:
         self.apiroutine.subroutine(self._get_existing_ports())
         connsetup = OVSDBConnectionSetup.createMatcher()
         bridgedown = OVSDBBridgeSetup.createMatcher(OVSDBBridgeSetup.DOWN)
         while True:
             yield (connsetup, bridgedown)
             e = self.apiroutine.event
             if self.apiroutine.matcher is connsetup:
                 self.monitor_routines.add(self.apiroutine.subroutine(self._get_ports(e.connection, e.connection.protocol)))
             else:
                 # Remove ports of the bridge
                 ports =  self.managed_ports.get((e.vhost, e.datapathid))
                 if ports is not None:
                     ports_original = ports
                     ports = [p for _,p in ports]
                     for p in ports:
                         if p['id']:
                             self._remove_interface_id(e.connection,
                                                       e.connection.protocol, e.datapathid, p)
                     newdpid = getattr(e, 'new_datapath_id', None)
                     buuid = e.bridgeuuid
                     if newdpid is not None:
                         # This bridge changes its datapath id
                         if buuid in self.bridge_datapathid and self.bridge_datapathid[buuid] == e.datapathid:
                             self.bridge_datapathid[buuid] = newdpid
                         def re_add_interfaces():
                             with closing(self.apiroutine.executeAll(
                                 [self._get_interface_info(e.connection, e.connection.protocol, buuid,
                                                           r['_uuid'], puuid)
                                  for puuid, r in ports_original])) as g:
                                 for m in g:
                                     yield m
                             add = list(itertools.chain(r[0] for r in self.apiroutine.retvalue))
                             for m in self.apiroutine.waitForSend(ModuleNotification(self.getServiceName(),
                                               'update', datapathid = e.datapathid,
                                               connection = e.connection,
                                               vhost = e.vhost,
                                               add = add, remove = [],
                                               reason = 'bridgeup'
                                               )):
                                 yield m
                         self.apiroutine.subroutine(re_add_interfaces())
                     else:
                         # The ports are removed
                         for puuid, _ in ports_original:
                             if puuid in self.ports_uuids[puuid] and self.ports_uuids[puuid] == buuid:
                                 del self.ports_uuids[puuid]
                     del self.managed_ports[(e.vhost, e.datapathid)]
                     self.scheduler.emergesend(ModuleNotification(self.getServiceName(),
                                               'update', datapathid = e.datapathid,
                                               connection = e.connection,
                                               vhost = e.vhost,
                                               add = [], remove = ports,
                                               reason = 'bridgedown'
                                               ))                            
     finally:
         for r in list(self.monitor_routines):
             r.close()
         self.scheduler.emergesend(ModuleNotification(self.getServiceName(), 'unsynchronized'))
Example #2
0
 def process_port(buuid, port_uuid, interfaces, remove_ids):
     if buuid not in self.bridge_datapathid:
         return
     datapath_id = self.bridge_datapathid[buuid]
     ports = self.managed_ports.get((protocol.vhost, datapath_id))
     remove = []
     if ports is not None:
         remove = [p for _,p in ports if p['_uuid'] in remove_ids]
         not_remove = [(_,p) for _,p in ports if p['_uuid'] not in remove_ids]
         ports[:len(not_remove)] = not_remove
         del ports[len(not_remove):]
     if interfaces:
         try:
             with closing(self.apiroutine.executeAll([self._get_interface_info(connection, protocol, buuid, iuuid, port_uuid)
                                                  for iuuid in interfaces])) as g:
                 for m in g:
                     yield m
             add = list(itertools.chain((r[0] for r in self.apiroutine.retvalue if r[0])))
         except Exception:
             self._logger.warning("Cannot get new port information", exc_info = True)
             add = []
     else:
         add = []
     if update:
         for m in self.apiroutine.waitForSend(ModuleNotification(self.getServiceName(), 'update', datapathid = datapath_id,
                                                                                                   connection = connection,
                                                                                                   vhost = protocol.vhost,
                                                                                                   add = add, remove = remove,
                                                                                                   reason = 'bridgemodify'
                                                                                                   )):
             yield m
Example #3
0
 def re_add_interfaces():
     with closing(
             self.apiroutine.executeAll([
                 self._get_interface_info(
                     e.connection,
                     e.connection.protocol, buuid,
                     r['_uuid'], puuid)
                 for puuid, r in ports_original
             ])) as g:
         for m in g:
             yield m
     add = list(
         itertools.chain(
             r[0]
             for r in self.apiroutine.retvalue))
     for m in self.apiroutine.waitForSend(
             ModuleNotification(
                 self.getServiceName(),
                 'update',
                 datapathid=e.datapathid,
                 connection=e.connection,
                 vhost=e.vhost,
                 add=add,
                 remove=[],
                 reason='bridgeup')):
         yield m
Example #4
0
 async def _get_existing_ports(self):
     r = await call_api(self.apiroutine, 'ovsdbmanager', 'getallconnections', {'vhost':None})
     matchers = []
     for c in r:
         self.monitor_routines.add(self.apiroutine.subroutine(self._get_ports(c, c.protocol)))
         matchers.append(OVSDBConnectionPortsSynchronized.createMatcher(c))
     await self.apiroutine.wait_for_all(*matchers)
     self._synchronized = True
     await self.apiroutine.wait_for_send(ModuleNotification(self.getServiceName(), 'synchronized'))
Example #5
0
 async def _manage_existing(self):
     result = await call_api(self.apiroutine, "openflowserver",
                             "getconnections", {})
     vb = self.vhostbind
     for c in result:
         if vb is None or c.protocol.vhost in vb:
             self._add_connection(c)
     self._synchronized = True
     await self.apiroutine.wait_for_send(
         ModuleNotification(self.getServiceName(), 'synchronized'))
Example #6
0
 def _get_ports(self, connection, protocol, onup=False, update=True):
     ofdef = connection.openflowdef
     dpid = connection.openflow_datapathid
     vhost = connection.protocol.vhost
     add = []
     try:
         if hasattr(ofdef, 'ofp_multipart_request'):
             # Openflow 1.3, use ofp_multipart_request to get ports
             for m in protocol.querymultipart(
                     ofdef.ofp_multipart_request(
                         type=ofdef.OFPMP_PORT_DESC), connection,
                     self.apiroutine):
                 yield m
             ports = self.managed_ports.setdefault((vhost, dpid), {})
             for msg in self.apiroutine.openflow_reply:
                 for p in msg.ports:
                     add.append(p)
                     ports[p.port_no] = p
         else:
             # Openflow 1.0, use features_request
             if onup:
                 # Use the features_reply on connection setup
                 reply = connection.openflow_featuresreply
             else:
                 request = ofdef.ofp_msg()
                 request.header.type = ofdef.OFPT_FEATURES_REQUEST
                 for m in protocol.querywithreply(request):
                     yield m
                 reply = self.apiroutine.retvalue
             ports = self.managed_ports.setdefault((vhost, dpid), {})
             for p in reply.ports:
                 add.append(p)
                 ports[p.port_no] = p
         if update:
             for m in self.apiroutine.waitForSend(
                     OpenflowPortSynchronized(connection)):
                 yield m
             self._logger.info(
                 "Openflow port synchronized on connection %r", connection)
             for m in self.apiroutine.waitForSend(
                     ModuleNotification(
                         self.getServiceName(),
                         'update',
                         datapathid=connection.openflow_datapathid,
                         connection=connection,
                         vhost=protocol.vhost,
                         add=add,
                         remove=[],
                         reason='connected')):
                 yield m
     except ConnectionResetException:
         pass
     except OpenflowProtocolException:
         pass
Example #7
0
 async def _get_existing_ports(self):
     r = await call_api(self.apiroutine, 'openflowmanager',
                        'getallconnections', {'vhost': None})
     await self.apiroutine.execute_all([
         self._get_ports(c, c.protocol, False, False) for c in r
         if c.openflow_auxiliaryid == 0
     ])
     self._synchronized = True
     self._logger.info("Openflow ports synchronized")
     await self.apiroutine.wait_for_send(
         ModuleNotification(self.getServiceName(), 'synchronized'))
Example #8
0
 def _manage_existing(self):
     for m in callAPI(self.apiroutine, "openflowserver", "getconnections",
                      {}):
         yield m
     vb = self.vhostbind
     for c in self.apiroutine.retvalue:
         if vb is None or c.protocol.vhost in vb:
             self._add_connection(c)
     self._synchronized = True
     for m in self.apiroutine.waitForSend(
             ModuleNotification(self.getServiceName(), 'synchronized')):
         yield m
Example #9
0
 def _get_existing_ports(self):
     for m in callAPI(self.apiroutine, 'ovsdbmanager', 'getallconnections', {'vhost':None}):
         yield m
     matchers = []
     for c in self.apiroutine.retvalue:
         self.monitor_routines.add(self.apiroutine.subroutine(self._get_ports(c, c.protocol)))
         matchers.append(OVSDBConnectionPortsSynchronized.createMatcher(c))
     for m in self.apiroutine.waitForAll(*matchers):
         yield m
     self._synchronized = True
     for m in self.apiroutine.waitForSend(ModuleNotification(self.getServiceName(), 'synchronized')):
         yield m
Example #10
0
 async def re_add_interfaces():
     result = await self.apiroutine.execute_all(
                     [self._get_interface_info(e.connection, e.connection.protocol, buuid,
                                               r['_uuid'], puuid)
                      for puuid, r in ports_original])
     add = list(itertools.chain(r[0] for r in result))
     await self.apiroutine.wait_for_send(ModuleNotification(self.getServiceName(),
                       'update', datapathid = e.datapathid,
                       connection = e.connection,
                       vhost = e.vhost,
                       add = add, remove = [],
                       reason = 'bridgeup'
                       ))
Example #11
0
 def _get_existing_ports(self):
     for m in callAPI(self.apiroutine, 'openflowmanager',
                      'getallconnections', {'vhost': None}):
         yield m
     for m in self.apiroutine.executeAll([
             self._get_ports(c, c.protocol, False, False)
             for c in self.apiroutine.retvalue
             if c.openflow_auxiliaryid == 0
     ]):
         yield m
     self._synchronized = True
     for m in self.apiroutine.waitForSend(
             ModuleNotification(self.getServiceName(), 'synchronized')):
         yield m
Example #12
0
 def _manage_existing(self):
     for m in callAPI(self.apiroutine, "jsonrpcserver", "getconnections", {}):
         yield m
     vb = self.vhostbind
     conns = self.apiroutine.retvalue
     for c in conns:
         if vb is None or c.protocol.vhost in vb:
             if not hasattr(c, '_ovsdb_manager_get_bridges'):
                 c._ovsdb_manager_get_bridges = self.apiroutine.subroutine(self._get_bridges(c, c.protocol))
     matchers = [OVSDBConnectionSetup.createMatcher(None, c, c.connmark) for c in conns]
     for m in self.apiroutine.waitForAll(*matchers):
         yield m
     self._synchronized = True
     for m in self.apiroutine.waitForSend(ModuleNotification(self.getServiceName(), 'synchronized')):
         yield m
Example #13
0
 def _manage_ports(self):
     try:
         self.apiroutine.subroutine(self._get_existing_ports())
         connsetup = OVSDBConnectionSetup.createMatcher()
         bridgedown = OVSDBBridgeSetup.createMatcher(OVSDBBridgeSetup.DOWN)
         while True:
             yield (connsetup, bridgedown)
             e = self.apiroutine.event
             if self.apiroutine.matcher is connsetup:
                 self.apiroutine.subroutine(
                     self._get_ports(e.connection, e.connection.protocol))
             else:
                 # Remove ports of the bridge
                 ports = self.managed_ports.get((e.vhost, e.datapathid))
                 if ports is not None:
                     ports = [p for _, p in ports]
                     for p in ports:
                         if p['id']:
                             self._remove_interface_id(
                                 e.connection, e.connection.protocol,
                                 e.datapathid, p)
                     del self.managed_ports[(e.vhost, e.datapathid)]
                     self.scheduler.emergesend(
                         ModuleNotification(self.getServiceName(),
                                            'update',
                                            datapathid=e.datapathid,
                                            connection=e.connection,
                                            vhost=e.vhost,
                                            add=[],
                                            remove=ports,
                                            reason='bridgedown'))
     finally:
         for r in self.monitor_routines:
             r.close()
         self.scheduler.emergesend(
             ModuleNotification(self.getServiceName(), 'unsynchronized'))
Example #14
0
 async def _manage_existing(self):
     conns = await call_api(self.apiroutine, "jsonrpcserver",
                            "getconnections", {})
     vb = self.vhostbind
     for c in conns:
         if vb is None or c.protocol.vhost in vb:
             if not hasattr(c, '_ovsdb_manager_get_bridges'):
                 c._ovsdb_manager_get_bridges = self.apiroutine.subroutine(
                     self._get_bridges(c, c.protocol))
     matchers = [
         OVSDBConnectionSetup.createMatcher(None, c, c.connmark)
         for c in conns if vb is None or c.protocol.vhost in vb
     ]
     await self.apiroutine.wait_for_all(*matchers)
     self._synchronized = True
     await self.apiroutine.wait_for_send(
         ModuleNotification(self.getServiceName(), 'synchronized'))
Example #15
0
 def _manage_ports(self):
     try:
         self.apiroutine.subroutine(self._get_existing_ports())
         conn_update = ModuleNotification.createMatcher('openflowmanager', 'update')
         port_status = OpenflowAsyncMessageEvent.createMatcher(of13.OFPT_PORT_STATUS, None, 0)
         while True:
             yield (conn_update, port_status)
             if self.apiroutine.matcher is port_status:
                 e = self.apiroutine.event
                 m = e.message
                 c = e.connection
                 if (c.protocol.vhost, c.openflow_datapathid) in self.managed_ports:
                     if m.reason == c.openflowdef.OFPPR_ADD:
                         # A new port is added
                         self.managed_ports[(c.protocol.vhost, c.openflow_datapathid)][m.desc.port_no] = m.desc
                         self.scheduler.emergesend(ModuleNotification(self.getServiceName(), 'update',
                                                                      datapathid = c.openflow_datapathid,
                                                                      connection = c,
                                                                      vhost = c.protocol.vhost,
                                                                      add = [m.desc], remove = [],
                                                                      reason = 'add'))
                     elif m.reason == c.openflowdef.OFPPR_DELETE:
                         try:
                             del self.managed_ports[(c.protocol.vhost, c.openflow_datapathid)][m.desc.port_no]
                             self.scheduler.emergesend(ModuleNotification(self.getServiceName(), 'update',
                                                                          datapathid = c.openflow_datapathid,
                                                                          connection = c,
                                                                          vhost = c.protocol.vhost,
                                                                          add = [], remove = [m.desc],
                                                                          reason = 'delete'))
                         except KeyError:
                             pass
                     elif m.reason == c.openflowdef.OFPPR_MODIFY:
                         try:
                             self.scheduler.emergesend(ModuleNotification(self.getServiceName(), 'modified',
                                                                          datapathid = c.openflow_datapathid,
                                                                          connection = c,
                                                                          vhost = c.protocol.vhost,
                                                                          old = self.managed_ports[(c.protocol.vhost, c.openflow_datapathid)][m.desc.port_no],
                                                                          new = m.desc,
                                                                          reason = 'modified'))
                         except KeyError:
                             self.scheduler.emergesend(ModuleNotification(self.getServiceName(), 'update',
                                                                          datapathid = c.openflow_datapathid,
                                                                          connection = c,
                                                                          vhost = c.protocol.vhost,
                                                                          add = [m.desc], remove = [],
                                                                          reason = 'add'))
                         self.managed_ports[(c.protocol.vhost, c.openflow_datapathid)][m.desc.port_no] = m.desc
             else:
                 e = self.apiroutine.event
                 for c in e.remove:
                     if c.openflow_auxiliaryid == 0 and (c.protocol.vhost, c.openflow_datapathid) in self.managed_ports:
                         self.scheduler.emergesend(ModuleNotification(self.getServiceName(), 'update',
                                              datapathid = c.openflow_datapathid,
                                              connection = c,
                                              vhost = c.protocol.vhost,
                                              add = [], remove = list(self.managed_ports[(c.protocol.vhost, c.openflow_datapathid)].values()),
                                              reason = 'disconnected'))
                         del self.managed_ports[(c.protocol.vhost, c.openflow_datapathid)]
                 for c in e.add:
                     if c.openflow_auxiliaryid == 0:
                         self.apiroutine.subroutine(self._get_ports(c, c.protocol, True, True))
     finally:
         self.scheduler.emergesend(ModuleNotification(self.getServiceName(), 'unsynchronized'))
Example #16
0
 def _wait_for_sync(self):
     if not self._synchronized:
         yield (ModuleNotification.createMatcher(self.getServiceName(),
                                                 'synchronized'), )
Example #17
0
 def _wait_for_sync(self):
     if not self._synchronized:
         yield (ModuleNotification.createMatcher(self.getServiceName(), 'synchronized'),)
Example #18
0
    def _manage_conns(self):
        vb = self.vhostbind
        self.apiroutine.subroutine(self._manage_existing(), False)
        try:
            if vb is not None:
                conn_up = OpenflowConnectionStateEvent.createMatcher(
                    state=OpenflowConnectionStateEvent.CONNECTION_SETUP,
                    _ismatch=lambda x: x.createby.vhost in vb)
                conn_down = OpenflowConnectionStateEvent.createMatcher(
                    state=OpenflowConnectionStateEvent.CONNECTION_DOWN,
                    _ismatch=lambda x: x.createby.vhost in vb)
            else:
                conn_up = OpenflowConnectionStateEvent.createMatcher(
                    state=OpenflowConnectionStateEvent.CONNECTION_SETUP)
                conn_down = OpenflowConnectionStateEvent.createMatcher(
                    state=OpenflowConnectionStateEvent.CONNECTION_DOWN)
            while True:
                yield (conn_up, conn_down)
                if self.apiroutine.matcher is conn_up:
                    e = self.apiroutine.event
                    remove = self._add_connection(e.connection)
                    self.scheduler.emergesend(
                        ModuleNotification(self.getServiceName(),
                                           'update',
                                           add=[e.connection],
                                           remove=remove))
                else:
                    e = self.apiroutine.event
                    conns = self.managed_conns.get(
                        (e.createby.vhost, e.datapathid))
                    remove = []
                    if conns is not None:
                        try:
                            conns.remove(e.connection)
                        except ValueError:
                            pass
                        else:
                            remove.append(e.connection)

                        if not conns:
                            del self.managed_conns[(e.createby.vhost,
                                                    e.datapathid)]
                        # Also delete from endpoint_conns
                        ep = _get_endpoint(e.connection)
                        econns = self.endpoint_conns.get(
                            (e.createby.vhost, ep))
                        if econns is not None:
                            try:
                                econns.remove(e.connection)
                            except ValueError:
                                pass
                            if not econns:
                                del self.endpoint_conns[(e.createby.vhost, ep)]
                    if remove:
                        self.scheduler.emergesend(
                            ModuleNotification(self.getServiceName(),
                                               'update',
                                               add=[],
                                               remove=remove))
        finally:
            self.scheduler.emergesend(
                ModuleNotification(self.getServiceName(), 'unsynchronized'))
Example #19
0
 def resync(self, datapathid, vhost=''):
     '''
     Resync with current ports
     '''
     # Sometimes when the OpenFlow connection is very busy, PORT_STATUS message may be dropped.
     # We must deal with this and recover from it
     # Save current manged_ports
     if (vhost, datapathid) not in self.managed_ports:
         self.apiroutine.retvalue = None
         return
     else:
         last_ports = set(self.managed_ports[(vhost, datapathid)].keys())
     add = set()
     remove = set()
     ports = {}
     for _ in range(0, 10):
         for m in callAPI(self.apiroutine, 'openflowmanager',
                          'getconnection', {
                              'datapathid': datapathid,
                              'vhost': vhost
                          }):
             yield m
         c = self.apiroutine.retvalue
         if c is None:
             # Disconnected, will automatically resync when reconnected
             self.apiroutine.retvalue = None
             return
         ofdef = c.openflowdef
         protocol = c.protocol
         try:
             if hasattr(ofdef, 'ofp_multipart_request'):
                 # Openflow 1.3, use ofp_multipart_request to get ports
                 for m in protocol.querymultipart(
                         ofdef.ofp_multipart_request(
                             type=ofdef.OFPMP_PORT_DESC), c,
                         self.apiroutine):
                     yield m
                 for msg in self.apiroutine.openflow_reply:
                     for p in msg.ports:
                         ports[p.port_no] = p
             else:
                 # Openflow 1.0, use features_request
                 request = ofdef.ofp_msg()
                 request.header.type = ofdef.OFPT_FEATURES_REQUEST
                 for m in protocol.querywithreply(request):
                     yield m
                 reply = self.apiroutine.retvalue
                 for p in reply.ports:
                     ports[p.port_no] = p
         except ConnectionResetException:
             break
         except OpenflowProtocolException:
             break
         else:
             if (vhost, datapathid) not in self.managed_ports:
                 self.apiroutine.retvalue = None
                 return
             current_ports = set(self.managed_ports[(vhost, datapathid)])
             # If a port is already removed
             remove.intersection_update(current_ports)
             # If a port is already added
             add.difference_update(current_ports)
             # If a port is not acquired, we do not add it
             acquired_keys = set(ports.keys())
             add.difference_update(acquired_keys)
             # Add and remove previous added/removed ports
             current_ports.difference_update(remove)
             current_ports.update(add)
             # If there are changed ports, the changed ports may or may not appear in the acquired port list
             # We only deal with following situations:
             # 1. If both lack ports, we add them
             # 2. If both have additional ports, we remote them
             to_add = acquired_keys.difference(
                 current_ports.union(last_ports))
             to_remove = current_ports.intersection(last_ports).difference(
                 acquired_keys)
             if not to_add and not to_remove and current_ports == last_ports:
                 break
             else:
                 add.update(to_add)
                 remove.update(to_remove)
                 current_ports.update(to_add)
                 current_ports.difference_update(to_remove)
                 last_ports = current_ports
     # Actual add and remove
     mports = self.managed_ports[(vhost, datapathid)]
     add_ports = []
     remove_ports = []
     for k in add:
         if k not in mports:
             add_ports.append(ports[k])
         mports[k] = ports[k]
     for k in remove:
         try:
             oldport = mports.pop(k)
         except KeyError:
             pass
         else:
             remove_ports.append(oldport)
     for m in self.apiroutine.waitForSend(
             ModuleNotification(self.getServiceName(),
                                'update',
                                datapathid=datapathid,
                                connection=c,
                                vhost=vhost,
                                add=add_ports,
                                remove=remove_ports,
                                reason='resync')):
         yield m
     self.apiroutine.retvalue = None
Example #20
0
 def _manage_ports(self):
     try:
         self.apiroutine.subroutine(self._get_existing_ports())
         conn_update = ModuleNotification.createMatcher(
             'openflowmanager', 'update')
         port_status = OpenflowAsyncMessageEvent.createMatcher(
             of13.OFPT_PORT_STATUS, None, 0)
         while True:
             yield (conn_update, port_status)
             if self.apiroutine.matcher is port_status:
                 e = self.apiroutine.event
                 m = e.message
                 c = e.connection
                 if (c.protocol.vhost,
                         c.openflow_datapathid) in self.managed_ports:
                     if m.reason == c.openflowdef.OFPPR_ADD:
                         # A new port is added
                         self.managed_ports[(c.protocol.vhost,
                                             c.openflow_datapathid
                                             )][m.desc.port_no] = m.desc
                         self.scheduler.emergesend(
                             ModuleNotification(
                                 self.getServiceName(),
                                 'update',
                                 datapathid=c.openflow_datapathid,
                                 connection=c,
                                 vhost=c.protocol.vhost,
                                 add=[m.desc],
                                 remove=[],
                                 reason='add'))
                     elif m.reason == c.openflowdef.OFPPR_DELETE:
                         try:
                             del self.managed_ports[(
                                 c.protocol.vhost,
                                 c.openflow_datapathid)][m.desc.port_no]
                             self.scheduler.emergesend(
                                 ModuleNotification(
                                     self.getServiceName(),
                                     'update',
                                     datapathid=c.openflow_datapathid,
                                     connection=c,
                                     vhost=c.protocol.vhost,
                                     add=[],
                                     remove=[m.desc],
                                     reason='delete'))
                         except KeyError:
                             pass
                     elif m.reason == c.openflowdef.OFPPR_MODIFY:
                         try:
                             self.scheduler.emergesend(
                                 ModuleNotification(
                                     self.getServiceName(),
                                     'modified',
                                     datapathid=c.openflow_datapathid,
                                     connection=c,
                                     vhost=c.protocol.vhost,
                                     old=self.managed_ports[(
                                         c.protocol.vhost,
                                         c.openflow_datapathid
                                     )][m.desc.port_no],
                                     new=m.desc,
                                     reason='modified'))
                         except KeyError:
                             self.scheduler.emergesend(
                                 ModuleNotification(
                                     self.getServiceName(),
                                     'update',
                                     datapathid=c.openflow_datapathid,
                                     connection=c,
                                     vhost=c.protocol.vhost,
                                     add=[m.desc],
                                     remove=[],
                                     reason='add'))
                         self.managed_ports[(c.protocol.vhost,
                                             c.openflow_datapathid
                                             )][m.desc.port_no] = m.desc
             else:
                 e = self.apiroutine.event
                 for c in e.remove:
                     if c.openflow_auxiliaryid == 0 and (
                             c.protocol.vhost,
                             c.openflow_datapathid) in self.managed_ports:
                         self.scheduler.emergesend(
                             ModuleNotification(
                                 self.getServiceName(),
                                 'update',
                                 datapathid=c.openflow_datapathid,
                                 connection=c,
                                 vhost=c.protocol.vhost,
                                 add=[],
                                 remove=list(self.managed_ports[(
                                     c.protocol.vhost,
                                     c.openflow_datapathid)].values()),
                                 reason='disconnected'))
                         del self.managed_ports[(c.protocol.vhost,
                                                 c.openflow_datapathid)]
                 for c in e.add:
                     if c.openflow_auxiliaryid == 0:
                         self.apiroutine.subroutine(
                             self._get_ports(c, c.protocol, True, True))
     finally:
         self.scheduler.emergesend(
             ModuleNotification(self.getServiceName(), 'unsynchronized'))
Example #21
0
        def process_bridge(buuid, uo):
            try:
                nv = uo['new']
                if 'datapath_id' in nv:
                    if ovsdb.getoptional(nv['datapath_id']) is None:
                        # This bridge is not initialized. Wait for the bridge to be initialized.
                        for m in callAPI(
                                self.apiroutine, 'ovsdbmanager', 'waitbridge',
                            {
                                'connection': connection,
                                'name': nv['name'],
                                'timeout': 5
                            }):
                            yield m
                        datapath_id = self.apiroutine.retvalue
                    else:
                        datapath_id = int(nv['datapath_id'], 16)
                    self.bridge_datapathid[buuid] = datapath_id
                elif buuid in self.bridge_datapathid:
                    datapath_id = self.bridge_datapathid[buuid]
                else:
                    # This should not happen, but just in case...
                    for m in callAPI(self.apiroutine, 'ovsdbmanager',
                                     'waitbridge', {
                                         'connection': connection,
                                         'name': nv['name'],
                                         'timeout': 5
                                     }):
                        yield m
                    datapath_id = self.apiroutine.retvalue
                    self.bridge_datapathid[buuid] = datapath_id
                if 'ports' in nv:
                    nset = set((p for _, p in ovsdb.getlist(nv['ports'])))
                else:
                    nset = set()
                if 'old' in uo:
                    ov = uo['old']
                    if 'ports' in ov:
                        oset = set((p for _, p in ovsdb.getlist(ov['ports'])))
                    else:
                        # new ports are not really added; it is only sent because datapath_id is modified
                        nset = set()
                        oset = set()
                    if 'datapath_id' in ov and ovsdb.getoptional(
                            ov['datapath_id']) is not None:
                        old_datapathid = int(ov['datapath_id'], 16)
                    else:
                        old_datapathid = datapath_id
                else:
                    oset = set()
                    old_datapathid = datapath_id
                # For every deleted port, remove the interfaces with this port _uuid
                remove = []
                add_routine = []
                for puuid in oset - nset:
                    remove += self._remove_all_interface(
                        connection, protocol, old_datapathid, puuid, buuid)
                # For every port not changed, check if the interfaces are modified;
                for puuid in oset.intersection(nset):
                    if puuid in port_update:
                        # The port is modified, there should be an 'old' set and 'new' set
                        pu = port_update[puuid]
                        if 'old' in pu:
                            poset = set((p for _, p in ovsdb.getlist(
                                pu['old']['interfaces'])))
                        else:
                            poset = set()
                        if 'new' in pu:
                            pnset = set((p for _, p in ovsdb.getlist(
                                pu['new']['interfaces'])))
                        else:
                            pnset = set()
                        # Remove old interfaces
                        remove += [
                            r for r in (self._remove_interface(
                                connection, protocol, datapath_id, iuuid,
                                puuid) for iuuid in (poset - pnset))
                            if r is not None
                        ]
                        # Prepare to add new interfaces
                        add_routine += [
                            self._get_interface_info(connection, protocol,
                                                     buuid, iuuid, puuid)
                            for iuuid in (pnset - poset)
                        ]
                # For every port added, add the interfaces
                def add_port_interfaces(puuid):
                    # If the uuid does not appear in update info, we have no choice but to query interfaces with select
                    # we cannot use data from other bridges; the port may be moved from a bridge which is not tracked
                    try:
                        method, params = ovsdb.transact(
                            'Open_vSwitch',
                            ovsdb.select('Port',
                                         [["_uuid", "==",
                                           ovsdb.uuid(puuid)]],
                                         ["interfaces"]))
                        for m in protocol.querywithreply(
                                method, params, connection, self.apiroutine):
                            yield m
                        r = self.apiroutine.jsonrpc_result[0]
                        if 'error' in r:
                            raise JsonRPCErrorResultException(
                                'Error when query interfaces from port ' +
                                repr(puuid) + ': ' + r['error'])
                        if r['rows']:
                            interfaces = ovsdb.getlist(
                                r['rows'][0]['interfaces'])
                            with closing(
                                    self.apiroutine.executeAll([
                                        self._get_interface_info(
                                            connection, protocol, buuid, iuuid,
                                            puuid) for _, iuuid in interfaces
                                    ])) as g:
                                for m in g:
                                    yield m
                            self.apiroutine.retvalue = list(
                                itertools.chain(
                                    r[0] for r in self.apiroutine.retvalue))
                        else:
                            self.apiroutine.retvalue = []
                    except JsonRPCProtocolException:
                        self.apiroutine.retvalue = []
                    except ConnectionResetException:
                        self.apiroutine.retvalue = []

                for puuid in nset - oset:
                    self.ports_uuids[puuid] = buuid
                    if puuid in port_update and 'new' in port_update[puuid] \
                            and 'old' not in port_update[puuid]:
                        # Add all the interfaces in 'new'
                        interfaces = ovsdb.getlist(
                            port_update[puuid]['new']['interfaces'])
                        add_routine += [
                            self._get_interface_info(connection, protocol,
                                                     buuid, iuuid, puuid)
                            for _, iuuid in interfaces
                        ]
                    else:
                        add_routine.append(add_port_interfaces(puuid))
                # Execute the add_routine
                try:
                    with closing(self.apiroutine.executeAll(add_routine)) as g:
                        for m in g:
                            yield m
                except:
                    add = []
                    raise
                else:
                    add = list(
                        itertools.chain(r[0]
                                        for r in self.apiroutine.retvalue))
                finally:
                    if update:
                        self.scheduler.emergesend(
                            ModuleNotification(self.getServiceName(),
                                               'update',
                                               datapathid=datapath_id,
                                               connection=connection,
                                               vhost=protocol.vhost,
                                               add=add,
                                               remove=remove,
                                               reason='bridgemodify'
                                               if 'old' in uo else 'bridgeup'))
            except JsonRPCProtocolException:
                pass
            except ConnectionResetException:
                pass
            except OVSDBBridgeNotAppearException:
                pass