address.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. #
  2. # Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
  3. #
  4. """Module providing access to network addresses
  5. """
  6. from __future__ import absolute_import
  7. __version__ = '1.0'
  8. __all__ = [
  9. 'AddressCache',
  10. 'Address']
  11. import datetime
  12. from .. import core as netlink
  13. from . import capi as capi
  14. from . import link as Link
  15. from .. import util as util
  16. class AddressCache(netlink.Cache):
  17. """Cache containing network addresses"""
  18. def __init__(self, cache=None):
  19. if not cache:
  20. cache = self._alloc_cache_name('route/addr')
  21. self._protocol = netlink.NETLINK_ROUTE
  22. self._nl_cache = cache
  23. def __getitem__(self, key):
  24. # Using ifindex=0 here implies that the local address itself
  25. # is unique, otherwise the first occurence is returned.
  26. return self.lookup(0, key)
  27. def lookup(self, ifindex, local):
  28. if type(local) is str:
  29. local = netlink.AbstractAddress(local)
  30. addr = capi.rtnl_addr_get(self._nl_cache, ifindex,
  31. local._nl_addr)
  32. if addr is None:
  33. raise KeyError()
  34. return Address._from_capi(addr)
  35. @staticmethod
  36. def _new_object(obj):
  37. return Address(obj)
  38. @staticmethod
  39. def _new_cache(cache):
  40. return AddressCache(cache=cache)
  41. class Address(netlink.Object):
  42. """Network address"""
  43. def __init__(self, obj=None):
  44. netlink.Object.__init__(self, 'route/addr', 'address', obj)
  45. self._rtnl_addr = self._obj2type(self._nl_object)
  46. @classmethod
  47. def _from_capi(cls, obj):
  48. return cls(capi.addr2obj(obj))
  49. @staticmethod
  50. def _obj2type(obj):
  51. return capi.obj2addr(obj)
  52. def __cmp__(self, other):
  53. # sort by:
  54. # 1. network link
  55. # 2. address family
  56. # 3. local address (including prefixlen)
  57. diff = self.ifindex - other.ifindex
  58. if diff == 0:
  59. diff = self.family - other.family
  60. if diff == 0:
  61. diff = capi.nl_addr_cmp(self.local, other.local)
  62. return diff
  63. @staticmethod
  64. def _new_instance(obj):
  65. return Address(obj)
  66. @property
  67. @netlink.nlattr(type=int, immutable=True, fmt=util.num)
  68. def ifindex(self):
  69. """interface index"""
  70. return capi.rtnl_addr_get_ifindex(self._rtnl_addr)
  71. @ifindex.setter
  72. def ifindex(self, value):
  73. link = Link.resolve(value)
  74. if not link:
  75. raise ValueError()
  76. self.link = link
  77. @property
  78. @netlink.nlattr(type=str, fmt=util.string)
  79. def link(self):
  80. link = capi.rtnl_addr_get_link(self._rtnl_addr)
  81. if not link:
  82. return None
  83. return Link.Link.from_capi(link)
  84. @link.setter
  85. def link(self, value):
  86. if type(value) is str:
  87. try:
  88. value = Link.resolve(value)
  89. except KeyError:
  90. raise ValueError()
  91. capi.rtnl_addr_set_link(self._rtnl_addr, value._rtnl_link)
  92. # ifindex is immutable but we assume that if _orig does not
  93. # have an ifindex specified, it was meant to be given here
  94. if capi.rtnl_addr_get_ifindex(self._orig) == 0:
  95. capi.rtnl_addr_set_ifindex(self._orig, value.ifindex)
  96. @property
  97. @netlink.nlattr(type=str, fmt=util.string)
  98. def label(self):
  99. """address label"""
  100. return capi.rtnl_addr_get_label(self._rtnl_addr)
  101. @label.setter
  102. def label(self, value):
  103. capi.rtnl_addr_set_label(self._rtnl_addr, value)
  104. @property
  105. @netlink.nlattr(type=str, fmt=util.string)
  106. def flags(self):
  107. """Flags
  108. Setting this property will *Not* reset flags to value you supply in
  109. Examples:
  110. addr.flags = '+xxx' # add xxx flag
  111. addr.flags = 'xxx' # exactly the same
  112. addr.flags = '-xxx' # remove xxx flag
  113. addr.flags = [ '+xxx', '-yyy' ] # list operation
  114. """
  115. flags = capi.rtnl_addr_get_flags(self._rtnl_addr)
  116. return capi.rtnl_addr_flags2str(flags, 256)[0].split(',')
  117. def _set_flag(self, flag):
  118. if flag.startswith('-'):
  119. i = capi.rtnl_addr_str2flags(flag[1:])
  120. capi.rtnl_addr_unset_flags(self._rtnl_addr, i)
  121. elif flag.startswith('+'):
  122. i = capi.rtnl_addr_str2flags(flag[1:])
  123. capi.rtnl_addr_set_flags(self._rtnl_addr, i)
  124. else:
  125. i = capi.rtnl_addr_str2flags(flag)
  126. capi.rtnl_addr_set_flags(self._rtnl_addr, i)
  127. @flags.setter
  128. def flags(self, value):
  129. if type(value) is list:
  130. for flag in value:
  131. self._set_flag(flag)
  132. else:
  133. self._set_flag(value)
  134. @property
  135. @netlink.nlattr(type=int, immutable=True, fmt=util.num)
  136. def family(self):
  137. """Address family"""
  138. fam = capi.rtnl_addr_get_family(self._rtnl_addr)
  139. return netlink.AddressFamily(fam)
  140. @family.setter
  141. def family(self, value):
  142. if not isinstance(value, netlink.AddressFamily):
  143. value = netlink.AddressFamily(value)
  144. capi.rtnl_addr_set_family(self._rtnl_addr, int(value))
  145. @property
  146. @netlink.nlattr(type=int, fmt=util.num)
  147. def scope(self):
  148. """Address scope"""
  149. scope = capi.rtnl_addr_get_scope(self._rtnl_addr)
  150. return capi.rtnl_scope2str(scope, 32)[0]
  151. @scope.setter
  152. def scope(self, value):
  153. if type(value) is str:
  154. value = capi.rtnl_str2scope(value)
  155. capi.rtnl_addr_set_scope(self._rtnl_addr, value)
  156. @property
  157. @netlink.nlattr(type=str, immutable=True, fmt=util.addr)
  158. def local(self):
  159. """Local address"""
  160. a = capi.rtnl_addr_get_local(self._rtnl_addr)
  161. return netlink.AbstractAddress(a)
  162. @local.setter
  163. def local(self, value):
  164. a = netlink.AbstractAddress(value)
  165. capi.rtnl_addr_set_local(self._rtnl_addr, a._nl_addr)
  166. # local is immutable but we assume that if _orig does not
  167. # have a local address specified, it was meant to be given here
  168. if capi.rtnl_addr_get_local(self._orig) is None:
  169. capi.rtnl_addr_set_local(self._orig, a._nl_addr)
  170. @property
  171. @netlink.nlattr(type=str, fmt=util.addr)
  172. def peer(self):
  173. """Peer address"""
  174. a = capi.rtnl_addr_get_peer(self._rtnl_addr)
  175. return netlink.AbstractAddress(a)
  176. @peer.setter
  177. def peer(self, value):
  178. a = netlink.AbstractAddress(value)
  179. capi.rtnl_addr_set_peer(self._rtnl_addr, a._nl_addr)
  180. @property
  181. @netlink.nlattr(type=str, fmt=util.addr)
  182. def broadcast(self):
  183. """Broadcast address"""
  184. a = capi.rtnl_addr_get_broadcast(self._rtnl_addr)
  185. return netlink.AbstractAddress(a)
  186. @broadcast.setter
  187. def broadcast(self, value):
  188. a = netlink.AbstractAddress(value)
  189. capi.rtnl_addr_set_broadcast(self._rtnl_addr, a._nl_addr)
  190. @property
  191. @netlink.nlattr(type=str, fmt=util.addr)
  192. def multicast(self):
  193. """multicast address"""
  194. a = capi.rtnl_addr_get_multicast(self._rtnl_addr)
  195. return netlink.AbstractAddress(a)
  196. @multicast.setter
  197. def multicast(self, value):
  198. try:
  199. a = netlink.AbstractAddress(value)
  200. except ValueError as err:
  201. raise AttributeError('multicast', err)
  202. capi.rtnl_addr_set_multicast(self._rtnl_addr, a._nl_addr)
  203. @property
  204. @netlink.nlattr(type=str, fmt=util.addr)
  205. def anycast(self):
  206. """anycast address"""
  207. a = capi.rtnl_addr_get_anycast(self._rtnl_addr)
  208. return netlink.AbstractAddress(a)
  209. @anycast.setter
  210. def anycast(self, value):
  211. a = netlink.AbstractAddress(value)
  212. capi.rtnl_addr_set_anycast(self._rtnl_addr, a._nl_addr)
  213. @property
  214. @netlink.nlattr(type=int, immutable=True, fmt=util.num)
  215. def valid_lifetime(self):
  216. """Valid lifetime"""
  217. msecs = capi.rtnl_addr_get_valid_lifetime(self._rtnl_addr)
  218. if msecs == 0xFFFFFFFF:
  219. return None
  220. else:
  221. return datetime.timedelta(seconds=msecs)
  222. @valid_lifetime.setter
  223. def valid_lifetime(self, value):
  224. capi.rtnl_addr_set_valid_lifetime(self._rtnl_addr, int(value))
  225. @property
  226. @netlink.nlattr(type=int, immutable=True, fmt=util.num)
  227. def preferred_lifetime(self):
  228. """Preferred lifetime"""
  229. msecs = capi.rtnl_addr_get_preferred_lifetime(self._rtnl_addr)
  230. if msecs == 0xFFFFFFFF:
  231. return None
  232. else:
  233. return datetime.timedelta(seconds=msecs)
  234. @preferred_lifetime.setter
  235. def preferred_lifetime(self, value):
  236. capi.rtnl_addr_set_preferred_lifetime(self._rtnl_addr, int(value))
  237. @property
  238. @netlink.nlattr(type=int, immutable=True, fmt=util.num)
  239. def create_time(self):
  240. """Creation time"""
  241. hsec = capi.rtnl_addr_get_create_time(self._rtnl_addr)
  242. return datetime.timedelta(milliseconds=10*hsec)
  243. @property
  244. @netlink.nlattr(type=int, immutable=True, fmt=util.num)
  245. def last_update(self):
  246. """Last update"""
  247. hsec = capi.rtnl_addr_get_last_update_time(self._rtnl_addr)
  248. return datetime.timedelta(milliseconds=10*hsec)
  249. def add(self, socket=None, flags=None):
  250. if not socket:
  251. socket = netlink.lookup_socket(netlink.NETLINK_ROUTE)
  252. if not flags:
  253. flags = netlink.NLM_F_CREATE
  254. ret = capi.rtnl_addr_add(socket._sock, self._rtnl_addr, flags)
  255. if ret < 0:
  256. raise netlink.KernelError(ret)
  257. def delete(self, socket, flags=0):
  258. """Attempt to delete this address in the kernel"""
  259. ret = capi.rtnl_addr_delete(socket._sock, self._rtnl_addr, flags)
  260. if ret < 0:
  261. raise netlink.KernelError(ret)
  262. ###################################################################
  263. # private properties
  264. #
  265. # Used for formatting output. USE AT OWN RISK
  266. @property
  267. def _flags(self):
  268. return ','.join(self.flags)
  269. def format(self, details=False, stats=False, nodev=False, indent=''):
  270. """Return address as formatted text"""
  271. fmt = util.MyFormatter(self, indent)
  272. buf = fmt.format('{a|local!b}')
  273. if not nodev:
  274. buf += fmt.format(' {a|ifindex}')
  275. buf += fmt.format(' {a|scope}')
  276. if self.label:
  277. buf += fmt.format(' "{a|label}"')
  278. buf += fmt.format(' <{a|_flags}>')
  279. if details:
  280. buf += fmt.nl('\t{t|broadcast} {t|multicast}') \
  281. + fmt.nl('\t{t|peer} {t|anycast}')
  282. if self.valid_lifetime:
  283. buf += fmt.nl('\t{s|valid-lifetime!k} '\
  284. '{a|valid_lifetime}')
  285. if self.preferred_lifetime:
  286. buf += fmt.nl('\t{s|preferred-lifetime!k} '\
  287. '{a|preferred_lifetime}')
  288. if stats and (self.create_time or self.last_update):
  289. buf += self.nl('\t{s|created!k} {a|create_time}'\
  290. ' {s|last-updated!k} {a|last_update}')
  291. return buf