You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
3.8 KiB
124 lines
3.8 KiB
#!/usr/bin/python
|
|
#
|
|
# Copyright 2017 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""Classes for generic netlink."""
|
|
|
|
import collections
|
|
from socket import * # pylint: disable=wildcard-import
|
|
import struct
|
|
|
|
import cstruct
|
|
import netlink
|
|
|
|
### Generic netlink constants. See include/uapi/linux/genetlink.h.
|
|
# The generic netlink control family.
|
|
GENL_ID_CTRL = 16
|
|
|
|
# Commands.
|
|
CTRL_CMD_GETFAMILY = 3
|
|
|
|
# Attributes.
|
|
CTRL_ATTR_FAMILY_ID = 1
|
|
CTRL_ATTR_FAMILY_NAME = 2
|
|
CTRL_ATTR_VERSION = 3
|
|
CTRL_ATTR_HDRSIZE = 4
|
|
CTRL_ATTR_MAXATTR = 5
|
|
CTRL_ATTR_OPS = 6
|
|
CTRL_ATTR_MCAST_GROUPS = 7
|
|
|
|
# Attributes netsted inside CTRL_ATTR_OPS.
|
|
CTRL_ATTR_OP_ID = 1
|
|
CTRL_ATTR_OP_FLAGS = 2
|
|
|
|
|
|
# Data structure formats.
|
|
# These aren't constants, they're classes. So, pylint: disable=invalid-name
|
|
Genlmsghdr = cstruct.Struct("genlmsghdr", "BBxx", "cmd version")
|
|
|
|
|
|
class GenericNetlink(netlink.NetlinkSocket):
|
|
"""Base class for all generic netlink classes."""
|
|
|
|
NL_DEBUG = []
|
|
|
|
def __init__(self):
|
|
super(GenericNetlink, self).__init__(netlink.NETLINK_GENERIC)
|
|
|
|
def _SendCommand(self, family, command, version, data, flags):
|
|
genlmsghdr = Genlmsghdr((command, version))
|
|
self._SendNlRequest(family, genlmsghdr.Pack() + data, flags)
|
|
|
|
def _Dump(self, family, command, version):
|
|
msg = Genlmsghdr((command, version))
|
|
return super(GenericNetlink, self)._Dump(family, msg, Genlmsghdr, "")
|
|
|
|
|
|
class GenericNetlinkControl(GenericNetlink):
|
|
"""Generic netlink control class.
|
|
|
|
This interface is used to manage other generic netlink families. We currently
|
|
use it only to find the family ID for address families of interest."""
|
|
|
|
def _DecodeOps(self, data):
|
|
ops = []
|
|
Op = collections.namedtuple("Op", ["id", "flags"])
|
|
while data:
|
|
# Skip the nest marker.
|
|
datalen, index, data = data[:2], data[2:4], data[4:]
|
|
|
|
nla, nla_data, data = self._ReadNlAttr(data)
|
|
if nla.nla_type != CTRL_ATTR_OP_ID:
|
|
raise ValueError("Expected CTRL_ATTR_OP_ID, got %d" % nla.nla_type)
|
|
op_id = struct.unpack("=I", nla_data)[0]
|
|
|
|
nla, nla_data, data = self._ReadNlAttr(data)
|
|
if nla.nla_type != CTRL_ATTR_OP_FLAGS:
|
|
raise ValueError("Expected CTRL_ATTR_OP_FLAGS, got %d" % nla.type)
|
|
op_flags = struct.unpack("=I", nla_data)[0]
|
|
|
|
ops.append(Op(op_id, op_flags))
|
|
return ops
|
|
|
|
def _Decode(self, command, msg, nla_type, nla_data):
|
|
"""Decodes generic netlink control attributes to human-readable format."""
|
|
|
|
name = self._GetConstantName(__name__, nla_type, "CTRL_ATTR_")
|
|
|
|
if name == "CTRL_ATTR_FAMILY_ID":
|
|
data = struct.unpack("=H", nla_data)[0]
|
|
elif name == "CTRL_ATTR_FAMILY_NAME":
|
|
data = nla_data.strip("\x00")
|
|
elif name in ["CTRL_ATTR_VERSION", "CTRL_ATTR_HDRSIZE", "CTRL_ATTR_MAXATTR"]:
|
|
data = struct.unpack("=I", nla_data)[0]
|
|
elif name == "CTRL_ATTR_OPS":
|
|
data = self._DecodeOps(nla_data)
|
|
else:
|
|
data = nla_data
|
|
|
|
return name, data
|
|
|
|
def GetFamily(self, name):
|
|
"""Returns the family ID for the specified family name."""
|
|
data = self._NlAttrStr(CTRL_ATTR_FAMILY_NAME, name)
|
|
self._SendCommand(GENL_ID_CTRL, CTRL_CMD_GETFAMILY, 0, data, netlink.NLM_F_REQUEST)
|
|
hdr, attrs = self._GetMsg(Genlmsghdr)
|
|
return attrs["CTRL_ATTR_FAMILY_ID"]
|
|
|
|
|
|
if __name__ == "__main__":
|
|
g = GenericNetlinkControl()
|
|
print(g.GetFamily("tcp_metrics"))
|