示例#1
0
文件: base.py 项目: fjacky/scion
 def _create_one_hop_path(self, egress_if):
     ts = int(SCIONTime.get_time())
     info = InfoOpaqueField.from_values(ts, self.addr.isd_as[0], hops=2)
     hf1 = HopOpaqueField.from_values(self.HOF_EXP_TIME, 0, egress_if)
     hf1.set_mac(self.of_gen_key, ts, None)
     # Return a path where second HF is empty.
     return SCIONPath.from_values(info, [hf1, HopOpaqueField()])
示例#2
0
 def update(self, pcb, reverse=False):
     """
     Insert path into database.
     Return the result of the operation.
     """
     first_ia = pcb.first_ia()
     last_ia = pcb.last_ia()
     if reverse:
         first_ia, last_ia = last_ia, first_ia
     if self._segment_ttl:
         now = int(SCIONTime.get_time())
         record = PathSegmentDBRecord(pcb, now + self._segment_ttl)
     else:
         record = PathSegmentDBRecord(pcb)
     with self._lock:
         recs = self._db(id=record.id, sibra=pcb.is_sibra())
         assert len(recs) <= 1, "PathDB contains > 1 path with the same ID"
         if not recs:
             self._db.insert(
                 record, record.id, first_ia[0], first_ia[1],
                 last_ia[0], last_ia[1], pcb.is_sibra())
             logging.debug("Added segment from %s to %s: %s",
                           first_ia, last_ia, pcb.short_desc())
             return DBResult.ENTRY_ADDED
         cur_rec = recs[0]['record']
         if pcb.get_expiration_time() < cur_rec.pcb.get_expiration_time():
             return DBResult.NONE
         cur_rec.pcb = pcb
         if self._segment_ttl:
             cur_rec.exp_time = now + self._segment_ttl
         else:
             cur_rec.exp_time = pcb.get_expiration_time()
         return DBResult.ENTRY_UPDATED
示例#3
0
文件: base.py 项目: forstern/scion
 def _zk_write_rev(self, data):
     hash_ = SHA256.new(data).hexdigest()
     try:
         self.rev_cache.store("%s-%s" % (hash_, SCIONTime.get_time()), data)
     except ZkNoConnection:
         logging.warning("Unable to store revocation(s) in shared path: "
                         "no connection to ZK")
示例#4
0
 def handle_pcbs_propagation(self):
     """
     Generate a new beacon or gets ready to forward the one received.
     """
     timestamp = int(SCIONTime.get_time())
     # Create beacon for downstream ASes.
     down_iof = InfoOpaqueField.from_values(timestamp, self.addr.isd_as[0])
     downstream_pcb = PathSegment.from_values(down_iof)
     propagated_pcbs = self.propagate_downstream_pcb(downstream_pcb)
     # Create beacon for core ASes.
     core_iof = InfoOpaqueField.from_values(timestamp, self.addr.isd_as[0])
     core_pcb = PathSegment.from_values(core_iof)
     propagated = self.propagate_core_pcb(core_pcb)
     for k, v in propagated.items():
         propagated_pcbs[k].extend(v)
     # Propagate received beacons. A core beacon server can only receive
     # beacons from other core beacon servers.
     beacons = []
     with self._rev_seg_lock:
         for ps in self.core_beacons.values():
             beacons.extend(ps.get_best_segments())
     for pcb in beacons:
         propagated = self.propagate_core_pcb(pcb)
         for k, v in propagated.items():
             propagated_pcbs[k].extend(v)
     self._log_propagations(propagated_pcbs)
示例#5
0
    def update_fidelity(self, path_policy):
        """
        Computes a path fidelity based on all path properties and considering
        the corresponding weights, which are stored in the path policy.

        :param dict path_policy: path policy.
        """
        self.fidelity = 0
        now = SCIONTime.get_time()
        self.fidelity += (path_policy.property_weights['PeerLinks'] *
                          self.peer_links)
        self.fidelity += (path_policy.property_weights['HopsLength'] /
                          self.hops_length)
        self.fidelity += (path_policy.property_weights['Disjointness'] *
                          self.disjointness)
        if now != 0:
            self.fidelity += (path_policy.property_weights['LastSentTime'] *
                              (now - self.last_sent_time) / now)
            self.fidelity += (path_policy.property_weights['LastSeenTime'] *
                              self.last_seen_time / now)
        self.fidelity += (path_policy.property_weights['DelayTime'] /
                          self.delay_time)
        self.fidelity += (path_policy.property_weights['ExpirationTime'] *
                          (self.expiration_time - now) / self.expiration_time)
        self.fidelity += (path_policy.property_weights['GuaranteedBandwidth'] *
                          self.guaranteed_bandwidth)
        self.fidelity += (path_policy.property_weights['AvailableBandwidth'] *
                          self.available_bandwidth)
        self.fidelity += (path_policy.property_weights['TotalBandwidth'] *
                          self.total_bandwidth)
示例#6
0
 def _add_req(self, key, request):
     self._expire_reqs(key)
     if not self._check(key):
         self._fetch(key, request)
     self._req_map[key].append((SCIONTime.get_time(), request))
     if self._labels:
         REQS_PENDING.labels(**self._labels).inc()
示例#7
0
文件: sciond.py 项目: MrShiyu/scion
 def get_paths(self, dst_ia, flags=(), flush=False):
     """Return a list of paths."""
     logging.debug("Paths requested for ISDAS=%s, flags=%s, flush=%s",
                   dst_ia, flags, flush)
     if flush:
         logging.info("Flushing PathDBs.")
         self._flush_path_dbs()
     if self.addr.isd_as == dst_ia or (
             self.addr.isd_as.any_as() == dst_ia and
             self.topology.is_core_as):
         # Either the destination is the local AS, or the destination is any
         # core AS in this ISD, and the local AS is in the core
         empty = SCIONPath()
         empty_meta = FwdPathMeta.from_values(empty, [], self.topology.mtu)
         return [empty_meta], SCIONDPathReplyError.OK
     deadline = SCIONTime.get_time() + self.PATH_REQ_TOUT
     e = threading.Event()
     self.requests.put(((dst_ia, flags), e))
     if not self._wait_for_events([e], deadline):
         logging.error("Query timed out for %s", dst_ia)
         return [], SCIONDPathReplyError.PS_TIMEOUT
     paths = self.path_resolution(dst_ia, flags=flags)
     error_code = (SCIONDPathReplyError.OK if paths
                   else SCIONDPathReplyError.NO_PATHS)
     return paths, error_code
示例#8
0
    def _check_property_ranges(self, pcb):
        """
        Checks whether any of the path properties has a value outside the
        predefined min-max range.

        :param pcb: beacon to analyze.
        :type pcb: :class:`PathSegment`
        """
        def _check_range(name, actual):
            range_ = self.property_ranges[name]
            if not range_:
                return
            if (actual < range_[0] or actual > range_[1]):
                reasons.append("%s: %d <= %d <= %d" %
                               (name, range_[0], actual, range_[1]))

        reasons = []
        _check_range("PeerLinks", pcb.get_n_peer_links())
        _check_range("HopsLength", pcb.get_n_hops())
        _check_range("DelayTime",
                     int(SCIONTime.get_time()) - pcb.get_timestamp())
        _check_range("GuaranteedBandwidth", 10)
        _check_range("AvailableBandwidth", 10)
        _check_range("TotalBandwidth", 10)
        return reasons
示例#9
0
    def expire(self, ttl):
        """
        Delete entries first seen more than `ttl` seconds ago.

        :param float ttl:
            Age (in seconds) after which cache entries should be removed.
        :raises:
            ZkNoConnection: if there's no connection to ZK.
            ZkNoNodeError: if a node disappears unexpectedly.
        """
        if not self._zk.is_connected():
            raise ZkNoConnection
        now = SCIONTime.get_time()
        count = 0
        for entry, ts in self._entries.items():
            if now - ts > ttl:
                full_path = os.path.join(self._path, entry)
                count += 1
                try:
                    self._kazoo.delete(full_path)
                except NoNodeError:
                    # This shouldn't happen, so raise an exception if it does.
                    raise ZkNoNodeError
                except (ConnectionLoss, SessionExpiredError):
                    raise ZkNoConnection from None
        if count:
            logging.debug("Expired %d old entries from %s", count, self._path)
示例#10
0
 def _add_req(self, key, request):
     self._req_map.setdefault(key, [])
     self._expire_reqs(key)
     if not self._check(key) and len(self._req_map[key]) == 0:
         # Don't already have the answer, and there were no outstanding
         # requests, so send a new query
         self._fetch(key, request)
     self._req_map[key].append((SCIONTime.get_time(), request))
示例#11
0
 def _remove_expired_segments(self):
     """Remove candidates if their expiration_time is up."""
     rec_ids = []
     now = SCIONTime.get_time()
     for candidate in self.candidates:
         if candidate.expiration_time <= now:
             rec_ids.append(candidate.id)
     self.remove_segments(rec_ids)
示例#12
0
文件: base.py 项目: stschwar/scion
 def _zk_write(self, data):
     hash_ = crypto_hash(data).hex()
     try:
         self.path_cache.store("%s-%s" % (hash_, SCIONTime.get_time()),
                               data)
     except ZkNoConnection:
         logging.warning("Unable to store segment(s) in shared path: "
                         "no connection to ZK")
示例#13
0
 def append_hop(self, isd_as, if_id, timestamp=None):  # pragma: no cover
     """
     Append hop's information as a new field in the extension.
     """
     # Check whether
     assert len(self.hops) < self._hdr_len
     if timestamp is None:
         # Truncate milliseconds to 2B
         timestamp = int(SCIONTime.get_time() * 1000) % 2**16
     self.hops.append((isd_as, if_id, timestamp))
示例#14
0
文件: main.py 项目: stschwar/scion
 def _share_object(self, pld, is_trc):
     """
     Share path segments (via ZK) with other path servers.
     """
     pld_packed = pld.pack()
     pld_hash = crypto_hash(pld_packed).hex()
     try:
         if is_trc:
             self.trc_cache.store(
                 "%s-%s" % (pld_hash, SCIONTime.get_time()), pld_packed)
         else:
             self.cc_cache.store("%s-%s" % (pld_hash, SCIONTime.get_time()),
                                 pld_packed)
     except ZkNoConnection:
         logging.warning("Unable to store %s in shared path: "
                         "no connection to ZK" % "TRC" if is_trc else "CC")
         return
     logging.debug("%s stored in ZK: %s" %
                   ("TRC" if is_trc else "CC", pld_hash))
示例#15
0
 def verify_hof(self, path, ingress=True):
     """Verify freshness and authentication of an opaque field."""
     ts = path.get_iof().timestamp
     hof = path.get_hof()
     prev_hof = path.get_hof_ver(ingress=ingress)
     if int(SCIONTime.get_time()) <= ts + hof.exp_time * EXP_TIME_UNIT:
         if not hof.verify_mac(self.of_gen_key, ts, prev_hof):
             raise SCIONOFVerificationError(hof, prev_hof)
     else:
         raise SCIONOFExpiredError(hof)
示例#16
0
 def update(self, pcb):
     """
     Update a candidate entry from a recent PCB.
     """
     assert self.id == pcb.get_hops_hash(hex=True)
     now = int(SCIONTime.get_time())
     self.pcb = copy.deepcopy(pcb)
     self.delay_time = now - pcb.get_timestamp()
     self.last_seen_time = now
     self.expiration_time = pcb.get_expiration_time()
示例#17
0
 def _wait_for_events(self, events, deadline):
     """
     Wait on a set of events, but only until the specified deadline. Returns
     the number of events that happened while waiting.
     """
     count = 0
     for e in events:
         if e.wait(max(0, deadline - SCIONTime.get_time())):
             count += 1
     return count
示例#18
0
    def _update_disjointness_db(self):
        """
        Update the disjointness database.

        Based on the current time, update the disjointness database keeping
        track of each path, AS, and interface previously sent.
        """
        now = SCIONTime.get_time()
        for k, v in self.disjointness.items():
            self.disjointness[k] = v * math.exp(self.last_dj_update - now)
        self.last_dj_update = now
示例#19
0
 def _expire_reqs(self, key):
     if key not in self._req_map:
         return
     now = SCIONTime.get_time()
     count = 0
     for ts, req in self._req_map[key][:]:
         if now - ts > self._ttl:
             count += 1
             self._req_map[key].remove((ts, req))
     if count:
         logging.debug("Expired %d requests for %s", count, key)
示例#20
0
 def __contains__(self, key):
     """ Return True if the dict has a key, else return False. """
     try:
         with self.lock:
             item = OrderedDict.__getitem__(self, key)
             if SCIONTime.get_time() - item[1] < self.max_age:
                 return True
             else:
                 del self[key]
     except KeyError:
         pass
     return False
示例#21
0
 def worker(self):
     """
     Worker thread that takes care of reading shared entries from ZK, and
     handling master election.
     """
     worker_cycle = 1.0
     start = SCIONTime.get_time()
     while self.run_flag.is_set():
         sleep_interval(start, worker_cycle, "CS.worker cycle",
                        self._quiet_startup())
         start = SCIONTime.get_time()
         try:
             self.zk.wait_connected()
             self.trc_cache.process()
             self.cc_cache.process()
             # Try to become a master.
             if self.zk.get_lock(lock_timeout=0, conn_timeout=0):
                 self.trc_cache.expire(worker_cycle * 10)
                 self.cc_cache.expire(worker_cycle * 10)
         except ZkNoConnection:
             logging.warning('worker(): ZkNoConnection')
             pass
示例#22
0
 def worker(self):
     """
     Worker thread that takes care of reading shared paths from ZK, and
     handling master election for core servers.
     """
     worker_cycle = 1.0
     start = SCIONTime.get_time()
     while self.run_flag.is_set():
         sleep_interval(start, worker_cycle, "cPS.worker cycle",
                        self._quiet_startup())
         start = SCIONTime.get_time()
         try:
             self.zk.wait_connected()
             self.path_cache.process()
             # Try to become a master.
             is_master = self.zk.get_lock(lock_timeout=0, conn_timeout=0)
             if is_master:
                 self.path_cache.expire(self.config.propagation_time * 10)
         except ZkNoConnection:
             logging.warning('worker(): ZkNoConnection')
             pass
         self._update_master()
         self._propagate_and_sync()
示例#23
0
 def request_ifstates(self):
     """
     Periodically request interface states from the BS.
     """
     pld = IFStateRequest.from_values()
     while self.run_flag.is_set():
         start_time = SCIONTime.get_time()
         logging.info("Sending IFStateRequest for all interfaces.")
         for bs in self.topology.beacon_servers:
             req = self._build_packet(bs.addr, dst_port=bs.port,
                                      payload=pld.copy())
             self.send(req, bs.addr, SCION_UDP_EH_DATA_PORT)
         sleep_interval(start_time, self.IFSTATE_REQ_INTERVAL,
                        "request_ifstates")
示例#24
0
 def __getitem__(self, key, with_age=False):
     """ Return the item of the dict.
     Raises a KeyError if key is not in the map.
     """
     with self.lock:
         item = OrderedDict.__getitem__(self, key)
         item_age = SCIONTime.get_time() - item[1]
         if item_age < self.max_age:
             if with_age:
                 return item[0], item_age
             else:
                 return item[0]
         else:
             del self[key]
             raise KeyError(key)
示例#25
0
 def _exp_call_records(self, recs):
     """Remove expired segments from the db."""
     now = int(SCIONTime.get_time())
     ret = []
     expired = []
     for r in recs:
         if r['record'].exp_time < now:
             expired.append(r)
             logging.debug("Path-Segment expired: %s",
                           r['record'].pcb.short_desc())
             continue
         ret.append(r)
     if expired:
         self._db.delete(expired)
     return ret
示例#26
0
 def __init__(self, pcb):
     """
     :param pcb: beacon to analyze.
     :type pcb: :class:`PathSegment`
     """
     assert isinstance(pcb, PathSegment), type(pcb)
     self.id = pcb.get_hops_hash(hex=True)
     self.peer_links = pcb.get_n_peer_links()
     self.hops_length = pcb.get_n_hops()
     self.fidelity = 0
     self.disjointness = 0
     self.last_sent_time = int(SCIONTime.get_time()) - self.DEFAULT_OFFSET
     self.guaranteed_bandwidth = 0
     self.available_bandwidth = 0
     self.total_bandwidth = 0
     self.update(pcb)
示例#27
0
    def verify_hof(self, path, ingress=True):
        """Verify freshness and authentication of an opaque field."""
        iof = path.get_iof()
        ts = iof.timestamp
        hof = path.get_hof()
        prev_hof = path.get_hof_ver(ingress=ingress)
        # Check that the interface in the current hop field matches the
        # interface in the router.

        if path.get_curr_if(ingress=ingress) != self.interface.if_id:
            raise SCIONIFVerificationError(hof, iof)

        if int(SCIONTime.get_time()) <= ts + hof.exp_time * EXP_TIME_UNIT:
            if not hof.verify_mac(self.of_gen_key, ts, prev_hof):
                raise SCIONOFVerificationError(hof, prev_hof)
        else:
            raise SCIONOFExpiredError(hof)
示例#28
0
 def get_paths(self, dst_ia, flags=()):
     """Return a list of paths."""
     logging.debug("Paths requested for %s %s", dst_ia, flags)
     if self.addr.isd_as == dst_ia or (self.addr.isd_as.any_as() == dst_ia
                                       and self.topology.is_core_as):
         # Either the destination is the local AS, or the destination is any
         # core AS in this ISD, and the local AS is in the core
         empty = SCIONPath()
         empty.mtu = self.topology.mtu
         return [empty]
     deadline = SCIONTime.get_time() + self.TIMEOUT
     e = threading.Event()
     self.requests.put(((dst_ia, flags), e))
     if not self._wait_for_events([e], deadline):
         logging.error("Query timed out for %s", dst_ia)
         return []
     return self.path_resolution(dst_ia, flags=flags)
示例#29
0
 def _expire_blocks(self):
     """
     Check the current reservation blocks and remove any that have expired.
     """
     now = SCIONTime.get_time()
     while True:
         if not self.blocks:
             raise SteadyPathErrorNoReservation
         act_block = self.blocks[0]
         exp = act_block.info.exp_ts()
         if now > exp:
             logging.debug("Reservation expired, removed: %s",
                           act_block.info)
             self.blocks.pop(0)
         elif len(self.blocks) > 1 and (now + SIBRA_TICK) > exp:
             # Don't use a block that expires this interval, if possible
             logging.debug("Reservation expiring soon, removed: %s",
                           act_block.info)
             self.blocks.pop(0)
         else:
             break
示例#30
0
    def _get(self, name):
        """
        Get an entry from the cache.

        :param str name: Name of the entry. E.g. ``"pcb0000002046"``.
        :return: The value of the entry.
        :rtype: :class:`bytes`
        :raises:
            ZkNoConnection: if there's no connection to ZK.
            ZkNoNodeError: if the entry does not exist.
        """
        full_path = os.path.join(self._path, name)
        try:
            data, _ = self._kazoo.get(full_path)
        except (ConnectionLoss, SessionExpiredError):
            raise ZkNoConnection from None
        except NoNodeError:
            self._entries.pop(name, None)
            raise ZkNoNodeError from None
        self._entries.setdefault(name, SCIONTime.get_time())
        return data