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 19from socket import * # pylint: disable=wildcard-import 20import struct 21 22import cstruct 23import genetlink 24import net_test 25import netlink 26 27 28### TCP metrics constants. See include/uapi/linux/tcp_metrics.h. 29# Family name and version 30TCP_METRICS_GENL_NAME = "tcp_metrics" 31TCP_METRICS_GENL_VERSION = 1 32 33# Message types. 34TCP_METRICS_CMD_GET = 1 35TCP_METRICS_CMD_DEL = 2 36 37# Attributes. 38TCP_METRICS_ATTR_UNSPEC = 0 39TCP_METRICS_ATTR_ADDR_IPV4 = 1 40TCP_METRICS_ATTR_ADDR_IPV6 = 2 41TCP_METRICS_ATTR_AGE = 3 42TCP_METRICS_ATTR_TW_TSVAL = 4 43TCP_METRICS_ATTR_TW_TS_STAMP = 5 44TCP_METRICS_ATTR_VALS = 6 45TCP_METRICS_ATTR_FOPEN_MSS = 7 46TCP_METRICS_ATTR_FOPEN_SYN_DROPS = 8 47TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS = 9 48TCP_METRICS_ATTR_FOPEN_COOKIE = 10 49TCP_METRICS_ATTR_SADDR_IPV4 = 11 50TCP_METRICS_ATTR_SADDR_IPV6 = 12 51TCP_METRICS_ATTR_PAD = 13 52 53 54class 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 135if __name__ == "__main__": 136 t = TcpMetrics() 137 print(t.DumpMetrics()) 138