• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python3
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
19from socket import *  # pylint: disable=wildcard-import
20import struct
21
22import binascii
23import cstruct
24import genetlink
25import net_test
26import netlink
27
28
29### TCP metrics constants. See include/uapi/linux/tcp_metrics.h.
30# Family name and version
31TCP_METRICS_GENL_NAME = "tcp_metrics"
32TCP_METRICS_GENL_VERSION = 1
33
34# Message types.
35TCP_METRICS_CMD_GET = 1
36TCP_METRICS_CMD_DEL = 2
37
38# Attributes.
39TCP_METRICS_ATTR_UNSPEC = 0
40TCP_METRICS_ATTR_ADDR_IPV4 = 1
41TCP_METRICS_ATTR_ADDR_IPV6 = 2
42TCP_METRICS_ATTR_AGE = 3
43TCP_METRICS_ATTR_TW_TSVAL = 4
44TCP_METRICS_ATTR_TW_TS_STAMP = 5
45TCP_METRICS_ATTR_VALS = 6
46TCP_METRICS_ATTR_FOPEN_MSS = 7
47TCP_METRICS_ATTR_FOPEN_SYN_DROPS = 8
48TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS = 9
49TCP_METRICS_ATTR_FOPEN_COOKIE = 10
50TCP_METRICS_ATTR_SADDR_IPV4 = 11
51TCP_METRICS_ATTR_SADDR_IPV6 = 12
52TCP_METRICS_ATTR_PAD = 13
53
54
55class TcpMetrics(genetlink.GenericNetlink):
56
57  NL_DEBUG = ["ALL"]
58
59  def __init__(self):
60    super(TcpMetrics, self).__init__()
61    # Generic netlink family IDs are dynamically assigned. Find ours.
62    ctrl = genetlink.GenericNetlinkControl()
63    self.family = ctrl.GetFamily(TCP_METRICS_GENL_NAME)
64
65  def _Decode(self, command, msg, nla_type, nla_data, nested):
66    """Decodes TCP metrics netlink attributes to human-readable format."""
67
68    name = self._GetConstantName(__name__, nla_type, "TCP_METRICS_ATTR_")
69
70    if name in ["TCP_METRICS_ATTR_ADDR_IPV4", "TCP_METRICS_ATTR_SADDR_IPV4"]:
71      data = inet_ntop(AF_INET, nla_data)
72    elif name in ["TCP_METRICS_ATTR_ADDR_IPV6", "TCP_METRICS_ATTR_SADDR_IPV6"]:
73      data = inet_ntop(AF_INET6, nla_data)
74    elif name in ["TCP_METRICS_ATTR_AGE"]:
75      data = struct.unpack("=Q", nla_data)[0]
76    elif name in ["TCP_METRICS_ATTR_TW_TSVAL", "TCP_METRICS_ATTR_TW_TS_STAMP"]:
77      data = struct.unpack("=I", nla_data)[0]
78    elif name == "TCP_METRICS_ATTR_FOPEN_MSS":
79      data = struct.unpack("=H", nla_data)[0]
80    elif name == "TCP_METRICS_ATTR_FOPEN_COOKIE":
81      data = nla_data
82    else:
83      data = binascii.hexlify(nla_data)
84
85    return name, data
86
87  def MaybeDebugCommand(self, command, unused_flags, data):
88    if "ALL" not in self.NL_DEBUG and command not in self.NL_DEBUG:
89      return
90    parsed = self._ParseNLMsg(data, genetlink.Genlmsghdr)
91
92  def _NlAttrSaddr(self, address):
93    if ":" not in address:
94      family = AF_INET
95      nla_type = TCP_METRICS_ATTR_SADDR_IPV4
96    else:
97      family = AF_INET6
98      nla_type = TCP_METRICS_ATTR_SADDR_IPV6
99    return self._NlAttrIPAddress(nla_type, family, address)
100
101  def _NlAttrTcpMetricsAddr(self, address, is_source):
102    version = net_test.GetAddressVersion(address)
103    family = net_test.GetAddressFamily(version)
104    if version == 5:
105      address = address.replace("::ffff:", "")
106    nla_name = "TCP_METRICS_ATTR_%s_IPV%d" % (
107        "SADDR" if is_source else "ADDR", version)
108    nla_type = globals()[nla_name]
109    return self._NlAttrIPAddress(nla_type, family, address)
110
111  def _NlAttrAddr(self, address):
112    return self._NlAttrTcpMetricsAddr(address, False)
113
114  def _NlAttrSaddr(self, address):
115    return self._NlAttrTcpMetricsAddr(address, True)
116
117  def DumpMetrics(self):
118    """Dumps all TCP metrics."""
119    return self._Dump(self.family, TCP_METRICS_CMD_GET, 1)
120
121  def GetMetrics(self, saddr, daddr):
122    """Returns TCP metrics for the specified src/dst pair."""
123    data = self._NlAttrSaddr(saddr) + self._NlAttrAddr(daddr)
124    self._SendCommand(self.family, TCP_METRICS_CMD_GET, 1, data,
125                      netlink.NLM_F_REQUEST)
126    hdr, attrs = self._GetMsg(genetlink.Genlmsghdr)
127    return attrs
128
129  def DelMetrics(self, saddr, daddr):
130    """Deletes TCP metrics for the specified src/dst pair."""
131    data = self._NlAttrSaddr(saddr) + self._NlAttrAddr(daddr)
132    self._SendCommand(self.family, TCP_METRICS_CMD_DEL, 1, data,
133                      netlink.NLM_F_REQUEST)
134
135
136if __name__ == "__main__":
137  t = TcpMetrics()
138  print(t.DumpMetrics())
139