Home | History | Annotate | Download | only in test
      1 #!/usr/bin/python
      2 #
      3 # Copyright 2017 The Android Open Source Project
      4 #
      5 # Licensed under the Apache License, Version 2.0 (the "License");
      6 # you may not use this file except in compliance with the License.
      7 # You may obtain a copy of the License at
      8 #
      9 # http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 # Unless required by applicable law or agreed to in writing, software
     12 # distributed under the License is distributed on an "AS IS" BASIS,
     13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 # See the License for the specific language governing permissions and
     15 # limitations under the License.
     16 
     17 """Generic netlink interface to TCP metrics."""
     18 
     19 from socket import *  # pylint: disable=wildcard-import
     20 import struct
     21 
     22 import cstruct
     23 import genetlink
     24 import net_test
     25 import netlink
     26 
     27 
     28 ### TCP metrics constants. See include/uapi/linux/tcp_metrics.h.
     29 # Family name and version
     30 TCP_METRICS_GENL_NAME = "tcp_metrics"
     31 TCP_METRICS_GENL_VERSION = 1
     32 
     33 # Message types.
     34 TCP_METRICS_CMD_GET = 1
     35 TCP_METRICS_CMD_DEL = 2
     36 
     37 # Attributes.
     38 TCP_METRICS_ATTR_UNSPEC = 0
     39 TCP_METRICS_ATTR_ADDR_IPV4 = 1
     40 TCP_METRICS_ATTR_ADDR_IPV6 = 2
     41 TCP_METRICS_ATTR_AGE = 3
     42 TCP_METRICS_ATTR_TW_TSVAL = 4
     43 TCP_METRICS_ATTR_TW_TS_STAMP = 5
     44 TCP_METRICS_ATTR_VALS = 6
     45 TCP_METRICS_ATTR_FOPEN_MSS = 7
     46 TCP_METRICS_ATTR_FOPEN_SYN_DROPS = 8
     47 TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS = 9
     48 TCP_METRICS_ATTR_FOPEN_COOKIE = 10
     49 TCP_METRICS_ATTR_SADDR_IPV4 = 11
     50 TCP_METRICS_ATTR_SADDR_IPV6 = 12
     51 TCP_METRICS_ATTR_PAD = 13
     52 
     53 
     54 class TcpMetrics(genetlink.GenericNetlink):
     55 
     56   NL_DEBUG = ["ALL"]
     57 
     58   def __init__(self):
     59     super(TcpMetrics, self).__init__()
     60     # Generic netlink family IDs are dynamically assigned. Find ours.
     61     ctrl = genetlink.GenericNetlinkControl()
     62     self.family = ctrl.GetFamily(TCP_METRICS_GENL_NAME)
     63 
     64   def _Decode(self, command, msg, nla_type, nla_data):
     65     """Decodes TCP metrics netlink attributes to human-readable format."""
     66 
     67     name = self._GetConstantName(__name__, nla_type, "TCP_METRICS_ATTR_")
     68 
     69     if name in ["TCP_METRICS_ATTR_ADDR_IPV4", "TCP_METRICS_ATTR_SADDR_IPV4"]:
     70       data = inet_ntop(AF_INET, nla_data)
     71     elif name in ["TCP_METRICS_ATTR_ADDR_IPV6", "TCP_METRICS_ATTR_SADDR_IPV6"]:
     72       data = inet_ntop(AF_INET6, nla_data)
     73     elif name in ["TCP_METRICS_ATTR_AGE"]:
     74       data = struct.unpack("=Q", nla_data)[0]
     75     elif name in ["TCP_METRICS_ATTR_TW_TSVAL", "TCP_METRICS_ATTR_TW_TS_STAMP"]:
     76       data = struct.unpack("=I", nla_data)[0]
     77     elif name == "TCP_METRICS_ATTR_FOPEN_MSS":
     78       data = struct.unpack("=H", nla_data)[0]
     79     elif name == "TCP_METRICS_ATTR_FOPEN_COOKIE":
     80       data = nla_data
     81     else:
     82       data = nla_data.encode("hex")
     83 
     84     return name, data
     85 
     86   def MaybeDebugCommand(self, command, unused_flags, data):
     87     if "ALL" not in self.NL_DEBUG and command not in self.NL_DEBUG:
     88       return
     89     parsed = self._ParseNLMsg(data, genetlink.Genlmsghdr)
     90 
     91   def _NlAttrSaddr(self, address):
     92     if ":" not in address:
     93       family = AF_INET
     94       nla_type = TCP_METRICS_ATTR_SADDR_IPV4
     95     else:
     96       family = AF_INET6
     97       nla_type = TCP_METRICS_ATTR_SADDR_IPV6
     98     return self._NlAttrIPAddress(nla_type, family, address)
     99 
    100   def _NlAttrTcpMetricsAddr(self, address, is_source):
    101     version = net_test.GetAddressVersion(address)
    102     family = net_test.GetAddressFamily(version)
    103     if version == 5:
    104       address = address.replace("::ffff:", "")
    105     nla_name = "TCP_METRICS_ATTR_%s_IPV%d" % (
    106         "SADDR" if is_source else "ADDR", version)
    107     nla_type = globals()[nla_name]
    108     return self._NlAttrIPAddress(nla_type, family, address)
    109 
    110   def _NlAttrAddr(self, address):
    111     return self._NlAttrTcpMetricsAddr(address, False)
    112 
    113   def _NlAttrSaddr(self, address):
    114     return self._NlAttrTcpMetricsAddr(address, True)
    115 
    116   def DumpMetrics(self):
    117     """Dumps all TCP metrics."""
    118     return self._Dump(self.family, TCP_METRICS_CMD_GET, 1)
    119 
    120   def GetMetrics(self, saddr, daddr):
    121     """Returns TCP metrics for the specified src/dst pair."""
    122     data = self._NlAttrSaddr(saddr) + self._NlAttrAddr(daddr)
    123     self._SendCommand(self.family, TCP_METRICS_CMD_GET, 1, data,
    124                       netlink.NLM_F_REQUEST)
    125     hdr, attrs = self._GetMsg(genetlink.Genlmsghdr)
    126     return attrs
    127 
    128   def DelMetrics(self, saddr, daddr):
    129     """Deletes TCP metrics for the specified src/dst pair."""
    130     data = self._NlAttrSaddr(saddr) + self._NlAttrAddr(daddr)
    131     self._SendCommand(self.family, TCP_METRICS_CMD_DEL, 1, data,
    132                       netlink.NLM_F_REQUEST)
    133 
    134 
    135 if __name__ == "__main__":
    136   t = TcpMetrics()
    137   print t.DumpMetrics()
    138