class PathTransOFPath(Serializable): """ Class used by PathTransportExt to encapsulate a path in data-plane format. """ NAME = "PathTransOFPath" MIN_LEN = 2 def __init__(self, raw=None): # pragma: no cover """ Initialize an instance of the class PathTransOFPath. :param raw: :type raw: """ self.src = None self.dst = None self.path = None super().__init__(raw) def _parse(self, raw): data = Raw(raw, self.NAME, self.MIN_LEN, min_=True) src_type = data.pop(1) dst_type = data.pop(1) self.src = SCIONAddr((src_type, data.get())) data.pop(len(self.src)) self.dst = SCIONAddr((dst_type, data.get())) data.pop(len(self.dst)) padding_len = len(data) % OpaqueField.LEN self.path = parse_path(data.pop(len(data) - padding_len)) @classmethod def from_values(cls, src, dst, path): # pragma: no cover inst = cls() inst.src = src inst.dst = dst inst.path = path return inst def pack(self): # pragma: no cover packed = [] packed.append(struct.pack("!B", self.src.host.TYPE)) packed.append(struct.pack("!B", self.dst.host.TYPE)) packed.append(self.src.pack()) packed.append(self.dst.pack()) packed.append(self.path.pack()) return b"".join(packed) def __len__(self): # pragma: no cover return len(self.pack()) def __str__(self): return "%s -> %s\n%s" % (self.src, self.dst, self.path)
class SCIONAddrHdr(Serializable): """SCION Address header.""" NAME = "SCIONAddrHdr" BLK_SIZE = 8 def __init__(self, raw_values=()): # pragma: no cover """ :param tuple raw: Tuple of src addr type, dst addr type, and raw addr bytes. """ super().__init__() self.src = None self.dst = None self._pad_len = None self._total_len = None if raw_values: self._parse(*raw_values) def _parse(self, src_type, dst_type, raw): data = Raw(raw, self.NAME, self.calc_lens(src_type, dst_type)[0]) self.src = SCIONAddr((src_type, data.get())) data.pop(len(self.src)) self.dst = SCIONAddr((dst_type, data.get())) data.pop(len(self.dst)) self.update() if self.src.host.TYPE == AddrType.SVC: raise SCMPBadSrcType("Invalid source type: SVC") @classmethod def from_values(cls, src, dst): # pragma: no cover """ src/dst must be a :any:`SCIONAddr` """ inst = cls() inst.src = src inst.dst = dst inst.update() return inst def pack(self): self.update() packed = [] packed.append(self.src.pack()) packed.append(self.dst.pack()) packed.append(bytes(self._pad_len)) raw = b"".join(packed) assert len(raw) % self.BLK_SIZE == 0 assert len(raw) == self._total_len return raw def validate(self): # pragma: no cover if self.dst.host.TYPE == AddrType.SVC and self.dst.host not in [ SVCType.BS, SVCType.PS, SVCType.CS, SVCType.SB ]: raise SCMPBadHost("Invalid dest SVC: %s" % self.dst.host.addr) def update(self): self._total_len, self._pad_len = self.calc_lens( self.src.host.TYPE, self.dst.host.TYPE) @classmethod def calc_lens(cls, src_type, dst_type): try: data_len = SCIONAddr.calc_len(src_type) except HostAddrInvalidType: raise SCMPBadSrcType("Unsupported src address type: %s" % src_type) from None try: data_len += SCIONAddr.calc_len(dst_type) except HostAddrInvalidType: raise SCMPBadDstType("Unsupported dst address type: %s" % dst_type) from None pad_len = calc_padding(data_len, cls.BLK_SIZE) total_len = data_len + pad_len assert total_len % cls.BLK_SIZE == 0 return total_len, pad_len def reverse(self): self.src, self.dst = self.dst, self.src self.update() def src_type(self): # pragma: no cover return self.src.host.TYPE def dst_type(self): # pragma: no cover return self.dst.host.TYPE def __len__(self): # pragma: no cover assert self._total_len is not None return self._total_len def __str__(self): return "%s(%sB): Src:<%s> Dst:<%s>" % (self.NAME, len(self), self.src, self.dst)