def _check(self, value, expected): inst = SCIONPath() inst._ofs = create_mock(["set"]) # Call inst._set_ofs("label", value) # Tests inst._ofs.set.assert_called_once_with("label", expected)
def test_empty(self): inst = SCIONPath() inst._ofs = [] # Call inst._init_of_idxs() # Tests ntools.eq_(inst._iof_idx, 0) ntools.eq_(inst._hof_idx, 0)
def test(self, iof): inst = SCIONPath() data = create_mock(["pop"]) inst._ofs = create_mock(["set"]) # Call ntools.eq_(inst._parse_iof(data, "label"), iof.return_value) # Tests data.pop.assert_called_once_with(iof.LEN) iof.assert_called_once_with(data.pop.return_value) inst._ofs.set.assert_called_once_with("label", [iof.return_value])
def test(self, hof): inst = SCIONPath() data = create_mock(["pop"]) inst._ofs = create_mock(["set"]) hof.side_effect = ["hof0", "hof1", "hof2"] # Call inst._parse_hofs(data, "label", 3) # Tests assert_these_calls(data.pop, [call(hof.LEN)] * 3) inst._ofs.set.assert_called_once_with("label", ["hof0", "hof1", "hof2"])
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
def _build_meta(self, ia=None, host=None, path=None, port=0, reuse=False, one_hop=False): if ia is None: ia = self.addr.isd_as if path is None: path = SCIONPath() if not one_hop: return self._DefaultMeta.from_values(ia, host, path, port=port, reuse=reuse) # One hop path extension in handled in a different way in TCP and UDP if self._DefaultMeta == TCPMetadata: return TCPMetadata.from_values(ia, host, path, port=port, reuse=reuse, flags=TCPFlags.ONEHOPPATH) return UDPMetadata.from_values(ia, host, path, port=port, reuse=reuse, ext_hdrs=[OneHopPathExt()])
def _join_xovr(up_segment, down_segment, point): """ Joins the supplied segments into a shortcut (xovr) fullpath. :param list up_segment: `up` :any:`PathSegment`. :param list down_segment: `down` :any:`PathSegment`. :param tuple point: Indexes of xovr point. :returns: :any:`CrossOverPath`. """ (up_index, down_index) = point up_iof, up_hofs, up_upstream_hof, up_mtu = \ _copy_segment_shortcut(up_segment, up_index) down_iof, down_hofs, down_upstream_hof, down_mtu = \ _copy_segment_shortcut(down_segment, down_index, up=False) up_iof.shortcut = down_iof.shortcut = True up_iof.peer = down_iof.peer = False up_hofs.append(up_upstream_hof) down_hofs.insert(0, down_upstream_hof) args = _shortcut_path_args(up_iof, up_hofs, down_iof, down_hofs) path = SCIONPath.from_values(*args) if_list = _build_shortcut_interface_list(up_segment, up_index, down_segment, down_index) mtu = _min_mtu(up_mtu, down_mtu) path_meta = FwdPathMeta.from_values(path, if_list, mtu) return [path_meta]
def _scmp_validate_error(self, pkt, e): if pkt.cmn_hdr.next_hdr == L4Proto.SCMP and pkt.ext_hdrs[0].error: # Never respond to an SCMP error with an SCMP error. logging.info( "Dropping SCMP error packet due to validation error. %s", e) return if isinstance(e, (SCMPBadIOFOffset, SCMPBadHOFOffset)): # Can't handle normally, as the packet isn't reversible. reply = self._scmp_bad_path_metadata(pkt, e) else: logging.warning("Error: %s", type(e)) reply = pkt.reversed_copy() args = () if isinstance(e, SCMPUnspecified): args = (str(e),) elif isinstance(e, (SCMPOversizePkt, SCMPBadPktLen)): args = (e.args[1],) # the relevant MTU. elif isinstance(e, (SCMPTooManyHopByHop, SCMPBadExtOrder, SCMPBadHopByHop)): args = e.args if isinstance(e, SCMPBadExtOrder): # Delete the problematic extension. del reply.ext_hdrs[args[0]] reply.convert_to_scmp_error(self.addr, e.CLASS, e.TYPE, pkt, *args) if pkt.addrs.src.isd_as == self.addr.isd_as: # No path needed for a local reply. reply.path = SCIONPath() next_hop, port = self.get_first_hop(reply) reply.update() self.send(reply, next_hop, port)
def _tcp_sock_from_meta(self, meta): assert meta.host if meta.ia is None: meta.ia = self.addr.isd_as if meta.path is None: meta.path = SCIONPath() dst = meta.get_addr() first_ip, first_port = self._get_first_hop(meta.path, dst) active = True try: # Create low-level TCP socket and connect sock = SCIONTCPSocket() sock.bind((self.addr, 0)) sock.connect(dst, meta.port, meta.path, first_ip, first_port, flags=meta.flags) except SCIONTCPError: log_exception( "TCP: connection init error, marking socket inactive") sock = None active = False # Create and return TCPSocketWrapper return TCPSocketWrapper(sock, dst, meta.path, active)
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()])
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 paths = self.path_resolution(dst_ia, flags=flags) if not paths: key = dst_ia, flags with self.req_path_lock: if key not in self.requested_paths: # No previous outstanding request self.requested_paths[key] = threading.Event() self._fetch_segments(key) e = self.requested_paths[key] if not e.wait(self.PATH_REQ_TOUT): 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
def _join_peer(up_segment, down_segment, point, peer_revs): """ Joins the supplied segments into a shortcut (peer) fullpath. :param list up_segment: `up` :any:`PathSegment`. :param list down_segment: `down` :any:`PathSegment`. :param tuple point: Indexes of peer point. :param RevCache peer_revs: Peering revocations. :returns: :any:`CrossOverPath`. """ (up_index, down_index) = point up_iof, up_hofs, up_upstream_hof, up_mtu = \ _copy_segment_shortcut(up_segment, up_index) down_iof, down_hofs, down_upstream_hof, down_mtu = \ _copy_segment_shortcut(down_segment, down_index, up=False) up_iof.shortcut = down_iof.shortcut = True up_iof.peer = down_iof.peer = True path_metas = [] for uph, dph, pm in _find_peer_hfs(up_segment.asm(up_index), down_segment.asm(down_index), peer_revs): um = min(up_mtu, pm) dm = min(down_mtu, pm) args = _shortcut_path_args(up_iof, up_hofs + [uph, up_upstream_hof], down_iof, [down_upstream_hof, dph] + down_hofs) path = SCIONPath.from_values(*args) if_list = _build_shortcut_interface_list(up_segment, up_index, down_segment, down_index, (uph, dph)) mtu = _min_mtu(um, dm) path_meta = FwdPathMeta.from_values(path, if_list, mtu) path_metas.append(path_meta) return path_metas
def _build_pkt(self): cmn_hdr, addr_hdr = build_base_hdrs(self.addr, self.dst) l4_hdr = self._create_l4_hdr() spkt = SCIONL4Packet.from_values(cmn_hdr, addr_hdr, SCIONPath(), [], l4_hdr) spkt.set_payload(self._create_payload(spkt)) spkt.update() return spkt
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)
def test_full(self, raw): inst = SCIONPath() inst._parse_iof = create_mock() inst._parse_hofs = create_mock() inst._init_of_idxs = create_mock() iof_list = [] for i in 2, 4, 6: iof = create_mock(["hops", "shortcut"]) iof.hops = i iof.shortcut = False iof_list.append(iof) inst._parse_iof.side_effect = iof_list data = create_mock() data.side_effect = ("A IOF", "A HOFS", "B IOF", "B HOFS", "C IOF", "C HOFS") raw.return_value = data # Call inst._parse("data") # Tests assert_these_calls(inst._parse_iof, [ call(data, inst.A_IOF), call(data, inst.B_IOF), call(data, inst.C_IOF) ]) assert_these_calls(inst._parse_hofs, [ call(data, inst.A_HOFS, 2), call(data, inst.B_HOFS, 4), call(data, inst.C_HOFS, 6) ]) inst._init_of_idxs.assert_called_once_with()
def _create_sibra_pkt(self, ext): """ Create a packet that uses a SIBRA path """ ext.setup = False ext.active_blocks = self.blocks[:1] cmn_hdr, addr_hdr, udp_hdr, payload = self._create_hdrs() return SCIONL4Packet.from_values(cmn_hdr, addr_hdr, SCIONPath(), [ext], udp_hdr, payload)
def test_xovr(self, build_list, path_args, copy_segment): up_segment, down_segment, point, exp_time = self._setup(path_args, copy_segment) path_meta = FwdPathMeta.from_values(SCIONPath(), [], 0, exp_time) ntools.eq_( path_combinator._join_xovr(up_segment, down_segment, point)[0], path_meta) copy_segment.assert_any_call(up_segment, 1) copy_segment.assert_any_call(down_segment, 2, cons_dir=True) ntools.eq_(build_list.call_count, 1)
def test_xovr(self, build_list, path_args, copy_segment): up_segment, down_segment, point = self._setup(path_args, copy_segment) path = SCIONPath.from_values() path.mtu = 1400 ntools.eq_( PathCombinator._join_xovr(up_segment, down_segment, point)[0], path) copy_segment.assert_any_call(up_segment, 1) copy_segment.assert_any_call(down_segment, 2, up=False) ntools.eq_(build_list.call_count, 1)
def test_peer(self, find_peers, build_list, path_args, copy_segment): up_segment, down_segment, point, exp_time = self._setup(path_args, copy_segment) find_peers.return_value = [("uph1", "dph1", 1500), ("uph2", "dph2", 1500)] peer_revs = create_mock() path_meta = FwdPathMeta.from_values(SCIONPath(), [], 0, exp_time) ntools.eq_(path_combinator._join_peer( up_segment, down_segment, point, peer_revs)[0], path_meta) copy_segment.assert_any_call(up_segment, 1) copy_segment.assert_any_call(down_segment, 2, cons_dir=True) ntools.eq_(build_list.call_count, 2)
def test_peer(self, find_peers, build_list, path_args, copy_segment): up_segment, down_segment, point = self._setup(path_args, copy_segment) find_peers.return_value = [("uph1", "dph1", 1500), ("uph2", "dph2", 1500)] path = SCIONPath.from_values() path.mtu = 1400 ntools.eq_( PathCombinator._join_peer(up_segment, down_segment, point)[0], path) copy_segment.assert_any_call(up_segment, 1) copy_segment.assert_any_call(down_segment, 2, up=False) ntools.eq_(build_list.call_count, 2)
def get_path(self, reverse_direction=False): """ Returns the list of HopOpaqueFields in the path. """ hofs = [] info = InfoOpaqueField(self.p.info) asms = list(self.iter_asms()) if reverse_direction: asms = reversed(asms) info.up_flag ^= True for asm in asms: hofs.append(asm.pcbm(0).hof()) return SCIONPath.from_values(info, hofs)
def accept(self): self._init_accept_sock() sockname = self._lwip_accept.getsockname()[-SOCK_PATH_LEN:] sockname = sockname.encode('ascii') # Confirmation from old (UNIX) socket. req = APICmd.ACCEPT + sockname self._exec_cmd(req, True) new_sock, _ = self._lwip_accept.accept() # Metadata (path and addr) from new (UNIX) socket. rep = get_lwip_reply(new_sock) self._handle_reply(req[:CMD_SIZE], rep) logging.debug("accept() raw reply: %s", rep) rep = rep[RESP_SIZE:] path_len, = struct.unpack("H", rep[:2]) rep = rep[2:] path = SCIONPath(rep[:path_len]) path.reverse() rep = rep[path_len:] addr = SCIONAddr((rep[0], rep[1:])) # Everything is ok, create new SCION TCP socket. sock = SCIONTCPSocket(new_sock, rpc_mode=False) return sock, addr, path
def _create_reg_pkt(self, type_, remote=False): if remote: dst_ia = self.remote path = self.seg.get_path(True) else: dst_ia = self.addr.isd_as path = SCIONPath() pcb = self._create_reg_pcb(remote) pld = PathRecordsReg.from_values({type_: [pcb]}) dest = SCIONAddr.from_values(dst_ia, SVCType.PS_A) cmn_hdr, addr_hdr = build_base_hdrs(self.addr, dest) udp_hdr = SCIONUDPHeader.from_values(self.addr, self._port, dest, 0) return SCIONL4Packet.from_values(cmn_hdr, addr_hdr, path, [], udp_hdr, pld)
def handle_one_hop_path(self, hdr, spkt, from_local_as): if len(spkt.path) != InfoOpaqueField.LEN + 2 * HopOpaqueField.LEN: logging.error("OneHopPathExt: incorrect path length.") return [(RouterFlag.ERROR,)] if not from_local_as: # Remote packet, create the 2nd Hop Field info = spkt.path.get_iof() hf1 = spkt.path.get_hof_ver(ingress=True) exp_time = OneHopPathExt.HOF_EXP_TIME hf2 = HopOpaqueField.from_values(exp_time, self.interface.if_id, 0) hf2.set_mac(self.of_gen_key, info.timestamp, hf1) # FIXME(PSz): quite brutal for now: spkt.path = SCIONPath.from_values(info, [hf1, hf2]) spkt.path.inc_hof_idx() return []
def _setup(self, xover=False, peer=False, shortcut=False, up_flag=True): inst = SCIONPath() inst._iof_idx = 0 inst._hof_idx = 0 iof = create_mock(["peer", "shortcut", "up_flag"]) iof.peer = peer iof.shortcut = shortcut iof.up_flag = up_flag inst.get_iof = create_mock() inst.get_iof.return_value = iof hof = create_mock(["xover"]) hof.xover = xover inst.get_hof = create_mock() inst.get_hof.return_value = hof inst._get_hof_ver_normal = create_mock() inst._ofs = create_mock(["get_by_idx"]) return inst, iof, hof
def test_non_peer(self): inst = SCIONPath() inst._ofs = [1] iof = create_mock(["peer"]) iof.peer = False inst.get_iof = create_mock() inst.get_iof.return_value = iof inst.inc_hof_idx = create_mock() # Call inst._init_of_idxs() # Tests ntools.eq_(inst._iof_idx, 0) ntools.eq_(inst._hof_idx, 0) inst.inc_hof_idx.assert_called_once_with()
def _build_packet(self, dst_host=None, path=None, ext_hdrs=(), dst_ia=None, payload=None, dst_port=0): if dst_host is None: dst_host = HostAddrNone() if dst_ia is None: dst_ia = self.addr.isd_as if path is None: path = SCIONPath() if payload is None: payload = PayloadRaw() dst_addr = SCIONAddr.from_values(dst_ia, dst_host) cmn_hdr, addr_hdr = build_base_hdrs(dst_addr, self.addr) udp_hdr = SCIONUDPHeader.from_values( self.addr, self._port, dst_addr, dst_port) return SCIONL4Packet.from_values( cmn_hdr, addr_hdr, path, ext_hdrs, udp_hdr, payload)
def _get_path_via_api(self): """ Test local API. """ data = self._try_sciond_api() path_len = data.pop(1) * 8 self.path = SCIONPath(data.pop(path_len)) haddr_type = haddr_get_type(data.pop(1)) data.pop(haddr_type.LEN) # first hop, unused here data.pop(2) # port number, unused here self.path.mtu = struct.unpack("!H", data.pop(2))[0] ifcount = data.pop(1) self.iflist = [] for i in range(ifcount): isd_as = ISD_AS(data.pop(ISD_AS.LEN)) ifid = struct.unpack("!H", data.pop(2))[0] self.iflist.append((isd_as, ifid))
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() exp_time = int(time.time()) + self.EMPTY_PATH_TTL empty_meta = FwdPathMeta.from_values(empty, [], self.topology.mtu, exp_time) return [empty_meta], SCIONDPathReplyError.OK paths = self.path_resolution(dst_ia, flags=flags) if not paths: key = dst_ia, flags with self.req_path_lock: r = self.requested_paths.get(key) if r is None: # No previous outstanding request req = PathSegmentReq.from_values(self.addr.isd_as, dst_ia, flags=flags) r = RequestState(req.copy()) self.requested_paths[key] = r self._fetch_segments(req) # Wait until event gets set. timeout = not r.e.wait(PATH_REQ_TOUT) with self.req_path_lock: if timeout: r.done() if key in self.requested_paths: del self.requested_paths[key] if timeout: logging.error("Query timed out for %s", dst_ia) return [], SCIONDPathReplyError.PS_TIMEOUT # Check if we can fulfill the path request. paths = self.path_resolution(dst_ia, flags=flags) if not paths: logging.error("No paths found for %s", dst_ia) return [], SCIONDPathReplyError.NO_PATHS return paths, SCIONDPathReplyError.OK
def _check_peer(self, xover, expected): inst = SCIONPath() inst._ofs = create_mock(["__len__", "get_by_idx"]) iof = create_mock(["peer"]) inst.get_iof = create_mock() inst.get_iof.return_value = iof hof = create_mock(["xover"]) hof.xover = xover inst._ofs.get_by_idx.return_value = hof inst.inc_hof_idx = create_mock() # Call inst._init_of_idxs() # Tests inst._ofs.get_by_idx.assert_called_once_with(1) ntools.eq_(inst._iof_idx, 0) ntools.eq_(inst._hof_idx, expected)