Exemplo n.º 1
0
 def __send_sync_pkt(self, addr, pkt_args, sock=None, vteps=None):
     """ Generates and sends a VXFLD sync pkt. to peer SNDs.
     :param addr: tuple composed of the recipients' IP addr and port
     :param pkt_args: maps inner packet attributes to their values
     :param sock: socket object
     :param vteps: maps VNIs to tuples composed of a VTEP's IP address,
                   holdtime and node identifier
     :type vteps: dict[int, (str, int, int)]
     :returns: a socket object
     :raises: socket.error
     """
     response_type = pkt_args.get('response_type', VXFLD.ResponseType.NONE)
     vxfld_pkt = VXFLD.Packet(type=VXFLD.MsgType.SYNC,
                              inner={'response_type': response_type})
     if vteps is not None:
         vxfld_pkt.data.vni_vteps = vteps
     try:
         if sock is None:
             sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
             sock.connect(addr)
         sock.sendall(str(vxfld_pkt))
         sock.shutdown(socket.SHUT_WR)
         return sock
     except socket.error as ex:
         # Socket not ready, buffer overflow etc.
         if sock is not None:
             sock.close()
         self._logger.error('Failed to send sync pkt: %s', ex)
         raise
Exemplo n.º 2
0
 def __handle_vxfld_msg(self, pkt, addr):
     """ HER: Handles a VXFLD message.
     :param pkt: socket buffer
     :param addr: tuple composed of the sender's address and port
     """
     # pylint: disable=no-member
     srcip, _ = addr
     self.__last_response = int(time.time())
     try:
         vxfld_pkt = VXFLD.Packet(pkt)
     except Exception as ex:  # pylint: disable=broad-except
         self._logger.error('Unknown VXFLD packet received from %s: %s',
                            srcip, ex.message)
         return
     refresh_pkt = vxfld_pkt.data
     if vxfld_pkt.type != VXFLD.MsgType.REFRESH:
         self._logger.warning('Unexpected vxfld pkt of type %d',
                              vxfld_pkt.type)
         return
     self._logger.info('Refresh msg from %s', srcip)
     self._logger.debug('Vteps %s', refresh_pkt.vni_vteps)
     # Compute the list of updated VNIs
     updated_vnis = {
         vni: set(iplist)
         for vni, iplist in refresh_pkt.vni_vteps.iteritems()
         if set(iplist) != self.__peerdb.get(vni, set())
     }
     if updated_vnis:
         self.__update_peerdb(updated_vnis)
Exemplo n.º 3
0
    def __send_refresh_pkt(self, addr, vteps, pkt_args):
        """ Sends a VXLAN refresh pkt. to the source addr.
        :param addr: tuple composed of the sender's IP addr and port
        :param vteps: maps VNIs to IP addresses
        :type vteps: dict[int, set(str) | list(str)]
        :param pkt_args: maps inner packet attributes to their values
        """

        # pylint: disable=missing-docstring
        def send_pkt(pkt_in, addr_in):
            with self.__isocketpool.item() as isock:
                try:
                    isock.sendto(str(pkt_in), addr_in)
                except Exception as ex:  # pylint: disable=broad-except
                    # Socket not ready, buffer overflow etc.
                    self._logger.error('Failed to send vxfld pkt reply: %s',
                                       ex)

        packet_count = 0
        holdtime = pkt_args.get('holdtime', self._conf.holdtime)
        identifier = pkt_args.get('identifier', _Fdb.DEFAULT_ID)
        version = pkt_args.get('version', VXFLD.VERSION)
        vxfld_pkt = None
        for vni, msgdata in vteps.iteritems():
            # Limit the refresh message size to max_packet_size.
            if (vxfld_pkt is None or VXFLD.BASE_PKT_SIZE + len(vxfld_pkt) +
                    vxfld_pkt.data.ipstr_len(vni, msgdata) >=
                    self._conf.max_packet_size):
                if vxfld_pkt is not None:
                    send_pkt(vxfld_pkt, addr)
                    packet_count += 1
                    if packet_count % self.__VXFLD_PKT_BURST_SIZE == 0:
                        eventlet.sleep(1)
                # Set originator to 0 so peers don't forward on.
                vxfld_pkt = (VXFLD.Packet(type=VXFLD.MsgType.REFRESH,
                                          version=version,
                                          inner={
                                              'holdtime': holdtime,
                                              'originator': False,
                                              'response_type':
                                              VXFLD.ResponseType.NONE,
                                              'identifier': identifier
                                          }))
            vxfld_pkt.data.vni_vteps = {vni: msgdata}
        if vxfld_pkt is not None and vxfld_pkt.data.vni_vteps:
            send_pkt(vxfld_pkt, addr)
Exemplo n.º 4
0
 def __handle_vxfld_msg(self, pkt, addr):
     """ Handles VXFLD messages.
     :param pkt: packet buffer
     :param addr: tuple composed of the sender's IP addr and port
     """
     # pylint: disable=no-member
     srcip, _ = addr
     try:
         pkt = VXFLD.Packet(pkt)
     except Exception as ex:  # pylint: disable=broad-except
         self._logger.error('Unknown VXFLD packet received from %s: %s',
                            srcip, ex.message)
         return
     if pkt.type == VXFLD.MsgType.REFRESH:
         self.__handle_vxfld_refresh(pkt, addr)
     elif pkt.type == VXFLD.MsgType.PROXY:
         self.__handle_vxfld_proxy(pkt, addr)
     else:
         self._logger.error('Unknown VXFLD packet type %s received from %s',
                            pkt.type, srcip)
Exemplo n.º 5
0
 def __send_vxfld_proxy(self, vxlan_pkt, addr):
     """ Generates and sends a VXFLD proxy packet to peer SNDs.
     :param vxlan_pkt: VXLAN data packet
     :param addr: tuple composed of the sender's IP addr and port
     """
     if self._conf.area is None:
         self._logger.error('Sending proxy packets requires config option '
                            '"area"')
         return
     srcip, srcport = addr
     pkt = VXFLD.Packet(type=VXFLD.MsgType.PROXY,
                        version=VXFLD.VERSION,
                        inner={
                            'area': self._conf.area,
                            'srcport': srcport
                        })
     pkt.data.srcip = srcip
     pkt.data.vxlan_pkt = vxlan_pkt
     pkt.data.add_proxy_ip(self._conf.proxy_id)
     self._logger.debug('Sending proxy packet from %s', srcip)
     self.__send_to_peers(pkt, self._conf.vxfld_proxy_servers)
Exemplo n.º 6
0
 def __send_refresh(self, vni_data, hold):
     """ Sends a refresh message to the SND.
     :param vni_data: maps VNIs to DeviceConfig objects
     :type vni_data: dict[int, DeviceConfig]
     :param hold: packet holdtime
     :returns: True if successful, False otherwise.
     """
     # Build the right data structure for the message
     # need msg_data as {svcnode: {vni: [local]}}
     pkt_pile = eventlet.GreenPile(self._pool)
     for svcnode, grouper in itertools.groupby(
             vni_data, lambda k: vni_data.get(k).svcnodeip):
         vxfld_pkt = None
         for vni in grouper:
             addrs = [vni_data.get(vni).localip]
             # Limit the refresh message to max_packet_size.
             if (vxfld_pkt is None or
                     VXFLD.BASE_PKT_SIZE + len(vxfld_pkt) +
                     vxfld_pkt.data.ipstr_len(vni, addrs) >=
                     self._conf.max_packet_size):
                 if vxfld_pkt is not None:
                     pkt_pile.spawn(self.__send_vxfld_pkt, vxfld_pkt,
                                    svcnode)
                 vxfld_pkt = (
                     VXFLD.Packet(type=VXFLD.MsgType.REFRESH,
                                  version=VXFLD.VERSION,
                                  inner={'holdtime': hold,
                                         'originator': True,
                                         'identifier':
                                             self._conf.node_id})
                 )
                 # We don't require an acknowledgement for delete messages.
                 if self._conf.head_rep and hold != 0:
                     vxfld_pkt.data.response_type = (
                         VXFLD.ResponseType.REQUESTED
                     )
             vxfld_pkt.data.vni_vteps = {vni: addrs}
         if vxfld_pkt is not None and vxfld_pkt.data.vni_vteps:
             pkt_pile.spawn(self.__send_vxfld_pkt, vxfld_pkt, svcnode)
     return not pkt_pile.used or reduce(operator.and_, pkt_pile, True)
Exemplo n.º 7
0
 def __handle_vxfld_sync(self, sock, addr):
     """ Handles vxsnd to vxsnd sync messages.
     :param sock: client socket
     :param addr: tuple composed of the sender's IP addr and port
     :returns: True if successful, False otherwise
     """
     # pylint: disable=no-member
     srcip, _ = addr
     try:
         self._logger.info('Sync packet from %s', srcip)
         pkt = VXFLD.Packet(b''.join(
             iter(lambda: sock.recv(self._conf.max_packet_size), b'')))
         if pkt.data.vni_vteps:
             self._logger.info('Sync data from %s', srcip)
             for vni, iplist in pkt.data.vni_vteps.iteritems():
                 for ele in iplist:
                     ip_addr, holdtime, identifier = ele
                     self.__fdb.update(vni, ip_addr, holdtime, identifier)
         if pkt.data.response_type == VXFLD.ResponseType.ALL:
             self._logger.info('Sync request from %s', srcip)
             vteps = collections.defaultdict(list)
             now = int(time.time())
             for vni in self.__fdb:
                 for entry in self.__fdb.get(vni, now):
                     addr, holdtime, identifier = entry
                     if holdtime > 0:
                         vteps[vni].append((addr, holdtime, identifier))
             pkt.data.vni_vteps = vteps
             pkt_args = {'response_type': VXFLD.ResponseType.NONE}
             self.__send_sync_pkt(addr, pkt_args, sock=sock, vteps=vteps)
         return True
     except Exception as ex:  # pylint: disable=broad-except
         self._logger.error('Failed to receive data from %s. %s', srcip, ex)
         if sock is not None:
             sock.close()
     return False