• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"""Classes for generic netlink."""
18
19import collections
20from socket import *  # pylint: disable=wildcard-import
21import struct
22
23import cstruct
24import netlink
25
26### Generic netlink constants. See include/uapi/linux/genetlink.h.
27# The generic netlink control family.
28GENL_ID_CTRL = 16
29
30# Commands.
31CTRL_CMD_GETFAMILY = 3
32
33# Attributes.
34CTRL_ATTR_FAMILY_ID = 1
35CTRL_ATTR_FAMILY_NAME = 2
36CTRL_ATTR_VERSION = 3
37CTRL_ATTR_HDRSIZE = 4
38CTRL_ATTR_MAXATTR = 5
39CTRL_ATTR_OPS = 6
40CTRL_ATTR_MCAST_GROUPS = 7
41
42# Attributes netsted inside CTRL_ATTR_OPS.
43CTRL_ATTR_OP_ID = 1
44CTRL_ATTR_OP_FLAGS = 2
45
46
47# Data structure formats.
48# These aren't constants, they're classes. So, pylint: disable=invalid-name
49Genlmsghdr = cstruct.Struct("genlmsghdr", "BBxx", "cmd version")
50
51
52class GenericNetlink(netlink.NetlinkSocket):
53  """Base class for all generic netlink classes."""
54
55  NL_DEBUG = []
56
57  def __init__(self):
58    super(GenericNetlink, self).__init__(netlink.NETLINK_GENERIC)
59
60  def _SendCommand(self, family, command, version, data, flags):
61    genlmsghdr = Genlmsghdr((command, version))
62    self._SendNlRequest(family, genlmsghdr.Pack() + data, flags)
63
64  def _Dump(self, family, command, version):
65    msg = Genlmsghdr((command, version))
66    return super(GenericNetlink, self)._Dump(family, msg, Genlmsghdr, "")
67
68
69class GenericNetlinkControl(GenericNetlink):
70  """Generic netlink control class.
71
72  This interface is used to manage other generic netlink families. We currently
73  use it only to find the family ID for address families of interest."""
74
75  def _DecodeOps(self, data):
76    ops = []
77    Op = collections.namedtuple("Op", ["id", "flags"])
78    while data:
79      # Skip the nest marker.
80      datalen, index, data = data[:2], data[2:4], data[4:]
81
82      nla, nla_data, data = self._ReadNlAttr(data)
83      if nla.nla_type != CTRL_ATTR_OP_ID:
84        raise ValueError("Expected CTRL_ATTR_OP_ID, got %d" % nla.nla_type)
85      op_id = struct.unpack("=I", nla_data)[0]
86
87      nla, nla_data, data = self._ReadNlAttr(data)
88      if nla.nla_type != CTRL_ATTR_OP_FLAGS:
89        raise ValueError("Expected CTRL_ATTR_OP_FLAGS, got %d" % nla.type)
90      op_flags = struct.unpack("=I", nla_data)[0]
91
92      ops.append(Op(op_id, op_flags))
93    return ops
94
95  def _Decode(self, command, msg, nla_type, nla_data):
96    """Decodes generic netlink control attributes to human-readable format."""
97
98    name = self._GetConstantName(__name__, nla_type, "CTRL_ATTR_")
99
100    if name == "CTRL_ATTR_FAMILY_ID":
101      data = struct.unpack("=H", nla_data)[0]
102    elif name == "CTRL_ATTR_FAMILY_NAME":
103      data = nla_data.strip("\x00")
104    elif name in ["CTRL_ATTR_VERSION", "CTRL_ATTR_HDRSIZE", "CTRL_ATTR_MAXATTR"]:
105      data = struct.unpack("=I", nla_data)[0]
106    elif name == "CTRL_ATTR_OPS":
107      data = self._DecodeOps(nla_data)
108    else:
109      data = nla_data
110
111    return name, data
112
113  def GetFamily(self, name):
114    """Returns the family ID for the specified family name."""
115    data = self._NlAttrStr(CTRL_ATTR_FAMILY_NAME, name)
116    self._SendCommand(GENL_ID_CTRL, CTRL_CMD_GETFAMILY, 0, data, netlink.NLM_F_REQUEST)
117    hdr, attrs = self._GetMsg(Genlmsghdr)
118    return attrs["CTRL_ATTR_FAMILY_ID"]
119
120
121if __name__ == "__main__":
122  g = GenericNetlinkControl()
123  print(g.GetFamily("tcp_metrics"))
124