Gentoo Archives: gentoo-portage-dev

From: Alec Warner <antarus@g.o>
To: gentoo-portage-dev@l.g.o
Subject: Re: [gentoo-portage-dev] [PATCH] Use RTNETLINK to configure the loopback interface
Date: Tue, 27 Aug 2019 16:24:44
Message-Id: CAAr7Pr_OxT5VG2e_cFAY0_-WLVOQvPt+Q=dkVHyvqPxk0dc2zg@mail.gmail.com
In Reply to: [gentoo-portage-dev] [PATCH] Use RTNETLINK to configure the loopback interface by Mike Gilbert
1 unit tests?
2
3 -A
4
5 On Mon, Aug 26, 2019 at 8:03 PM Mike Gilbert <floppym@g.o> wrote:
6
7 > This eliminates the dependency on iproute2 on Linux.
8 >
9 > Signed-off-by: Mike Gilbert <floppym@g.o>
10 > ---
11 > lib/portage/process.py | 25 ++++------
12 > lib/portage/util/netlink.py | 91 +++++++++++++++++++++++++++++++++++++
13 > 2 files changed, 100 insertions(+), 16 deletions(-)
14 > create mode 100644 lib/portage/util/netlink.py
15 >
16 > diff --git a/lib/portage/process.py b/lib/portage/process.py
17 > index 2a2cbd972..bb4462c7f 100644
18 > --- a/lib/portage/process.py
19 > +++ b/lib/portage/process.py
20 > @@ -10,7 +10,6 @@ import multiprocessing
21 > import platform
22 > import signal
23 > import socket
24 > -import struct
25 > import subprocess
26 > import sys
27 > import traceback
28 > @@ -489,17 +488,6 @@ def _configure_loopback_interface():
29 > Configure the loopback interface.
30 > """
31 >
32 > - IFF_UP = 0x1
33 > - ifreq = struct.pack('16sh', b'lo', IFF_UP)
34 > - SIOCSIFFLAGS = 0x8914
35 > -
36 > - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
37 > - try:
38 > - fcntl.ioctl(sock, SIOCSIFFLAGS, ifreq)
39 > - except IOError as e:
40 > - writemsg("Unable to enable loopback interface: %s\n" %
41 > e.strerror, noiselevel=-1)
42 > - sock.close()
43 > -
44 > # We add some additional addresses to work around odd behavior in
45 > glibc's
46 > # getaddrinfo() implementation when the AI_ADDRCONFIG flag is set.
47 > #
48 > @@ -514,12 +502,17 @@ def _configure_loopback_interface():
49 > # Bug: https://bugs.gentoo.org/690758
50 > # Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=12377#c13
51 >
52 > + from portage.util.netlink import RtNetlink
53 > +
54 > try:
55 > - subprocess.call(['ip', 'address', 'add', '10.0.0.1/8',
56 > 'dev', 'lo'])
57 > - if _has_ipv6():
58 > - subprocess.call(['ip', 'address', 'add',
59 > 'fd00::1/8', 'dev', 'lo'])
60 > + with RtNetlink() as rtnl:
61 > + ifindex = rtnl.get_link_ifindex(b'lo')
62 > + rtnl.set_link_up(ifindex)
63 > + rtnl.add_address(ifindex, socket.AF_INET,
64 > '10.0.0.1', 8)
65 > + if _has_ipv6():
66 > + rtnl.add_address(ifindex, socket.AF_INET6,
67 > 'fd::1', 8)
68 > except EnvironmentError as e:
69 > - writemsg("Error calling 'ip': %s\n" % e.strerror,
70 > noiselevel=-1)
71 > + writemsg("Unable to configure loopback interface: %s\n" %
72 > e.strerror, noiselevel=-1)
73 >
74 > def _exec(binary, mycommand, opt_name, fd_pipes,
75 > env, gid, groups, uid, umask, cwd,
76 > diff --git a/lib/portage/util/netlink.py b/lib/portage/util/netlink.py
77 > new file mode 100644
78 > index 000000000..5b18b8f95
79 > --- /dev/null
80 > +++ b/lib/portage/util/netlink.py
81 > @@ -0,0 +1,91 @@
82 > +# Copyright 2019 Gentoo Authors
83 > +# Distributed under the terms of the GNU General Public License v2
84 > +
85 > +from io import BytesIO
86 > +from os import strerror
87 > +from struct import Struct
88 > +
89 > +from socket import (
90 > + AF_NETLINK, AF_UNSPEC,
91 > + MSG_PEEK, MSG_TRUNC,
92 > + NETLINK_ROUTE,
93 > + SOCK_DGRAM,
94 > + inet_pton, socket,
95 > +)
96 > +
97 > +IFA_LOCAL = 2
98 > +IFF_UP = 0x1
99 > +IFLA_IFNAME = 3
100 > +NLMSG_ERROR = 2
101 > +RTM_NEWLINK = 16
102 > +RTM_GETLINK = 18
103 > +RTM_NEWADDR = 20
104 > +NLM_F_REQUEST = 0x1
105 > +NLM_F_ACK = 0x4
106 > +NLM_F_EXCL = 0x200
107 > +NLM_F_CREATE = 0x400
108 > +
109 > +nlmsghdr = Struct('=IHHII')
110 > +nlmsgerr = Struct('i')
111 > +rtattr = Struct('HH')
112 > +ifinfomsg = Struct('BHiII')
113 > +ifaddrmsg = Struct('BBBBi')
114 > +
115 > +def create_nlmsg(nlmsg_type, nlmsg_flags, nlmsg_seq, nlmsg_pid, data):
116 > + nlmsg_len = nlmsghdr.size + len(data)
117 > + return nlmsghdr.pack(nlmsg_len, nlmsg_type, nlmsg_flags,
118 > nlmsg_seq, nlmsg_pid) + data
119 > +
120 > +def create_rtattr(rta_type, data):
121 > + rta_len = rtattr.size + len(data)
122 > + return rtattr.pack(rta_len, rta_type) + data
123 > +
124 > +def parse_message(msg):
125 > + buf = BytesIO(msg)
126 > + hdr = nlmsghdr.unpack(buf.read(nlmsghdr.size))
127 > + if hdr[1] == NLMSG_ERROR:
128 > + err = nlmsgerr.unpack(buf.read(nlmsgerr.size))
129 > + error = -err[0]
130 > + if error != 0:
131 > + raise OSError(error, strerror(error))
132 > + elif hdr[1] == RTM_NEWLINK:
133 > + return ifinfomsg.unpack(buf.read(ifinfomsg.size))
134 > +
135 > +class RtNetlink:
136 > + def __init__(self):
137 > + self.sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)
138 > + self.addr = (0, 0)
139 > + self.sock.bind(self.addr)
140 > +
141 > + def __enter__(self):
142 > + return self
143 > +
144 > + def __exit__(self, exc_type, exc_value, traceback):
145 > + self.sock.close()
146 > +
147 > + def send_message(self, msg):
148 > + self.sock.sendto(msg, self.addr)
149 > + # Messages are variable length, but 128 is enough for the
150 > the ones we care about.
151 > + resp = self.sock.recv(128)
152 > + return parse_message(resp)
153 > +
154 > + def get_link_ifindex(self, ifname):
155 > + body = ifinfomsg.pack(AF_UNSPEC, 0, 0, 0, 0)
156 > + body += create_rtattr(IFLA_IFNAME, ifname)
157 > + flags = NLM_F_REQUEST
158 > + msg = create_nlmsg(RTM_GETLINK, flags, 1, 0, body)
159 > + resp = self.send_message(msg)
160 > + return resp[2]
161 > +
162 > + def set_link_up(self, ifindex):
163 > + body = ifinfomsg.pack(AF_UNSPEC, 0, ifindex, IFF_UP,
164 > IFF_UP)
165 > + flags = NLM_F_REQUEST|NLM_F_ACK
166 > + msg = create_nlmsg(RTM_NEWLINK, flags, 1, 0, body)
167 > + self.send_message(msg)
168 > +
169 > + def add_address(self, ifindex, family, address, prefixlen):
170 > + body = ifaddrmsg.pack(family, prefixlen, 0, 0, ifindex)
171 > + addr = inet_pton(family, address)
172 > + body += create_rtattr(IFA_LOCAL, addr)
173 > + flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL|NLM_F_CREATE
174 > + msg = create_nlmsg(RTM_NEWADDR, flags, 1, 0, body)
175 > + self.send_message(msg)
176 > --
177 > 2.23.0
178 >
179 >
180 >

Replies