ifstate 1.13.6__py3-none-any.whl → 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,15 +3,33 @@ import pyroute2.netns
3
3
 
4
4
  import os
5
5
 
6
+ def deep_update(d, u):
7
+ """update the nested dict `d` with values from `u`"""
8
+ for k, v in u.items():
9
+ if isinstance(v, dict):
10
+ d[k] = deep_update(d.get(k, {}), v)
11
+ else:
12
+ d[k] = v
13
+ return d
6
14
 
7
15
  class Sysctl():
8
16
  def __init__(self, netns):
9
- self.sysctls = {}
17
+ self.sysctls = {
18
+ "all": {
19
+ "ipv6": {
20
+ "optimistic_dad": 1
21
+ }
22
+ }
23
+ }
10
24
  self.globals = {}
11
25
  self.netns = netns
12
26
 
13
27
  def add(self, iface, sysctl):
14
- self.sysctls[iface] = sysctl
28
+ # deeply apply changes to the default/previously defined values
29
+ if iface in self.sysctls:
30
+ self.sysctls[iface] = deep_update(self.sysctls[iface], sysctl)
31
+ else:
32
+ self.sysctls[iface] = sysctl
15
33
 
16
34
  def add_global(self, proto, sysctl):
17
35
  self.globals[proto] = sysctl
libifstate/tc/__init__.py CHANGED
@@ -254,7 +254,7 @@ class TC():
254
254
  return changes
255
255
 
256
256
  def apply(self, do_apply):
257
- excpts = ExceptionCollector(ifname=self.iface)
257
+ excpts = ExceptionCollector(self.iface, self.netns)
258
258
 
259
259
  # get ifindex
260
260
  self.idx = next(iter(self.netns.ipr.link_lookup(ifname=self.iface)), None)
libifstate/util.py CHANGED
@@ -1,7 +1,9 @@
1
1
  import libifstate.exception
2
2
  from libifstate.log import logger, IfStateLogging
3
- from pyroute2 import IPRoute, NetNS, netns
3
+ import pyroute2
4
+ from pyroute2 import IPRoute, IW, NetNS
4
5
 
6
+ from pyroute2 import NetlinkError
5
7
  from pyroute2.netlink.rtnl.tcmsg import tcmsg
6
8
  from pyroute2.netlink.rtnl import RTM_DELTFILTER, RTM_NEWNSID
7
9
  from pyroute2.netlink.rtnl.nsidmsg import nsidmsg
@@ -17,33 +19,45 @@ except ModuleNotFoundError:
17
19
  # pyroute2 >= 0.6
18
20
  from pr2modules.ethtool.ioctl import SIOCETHTOOL
19
21
 
22
+ import atexit
20
23
  import socket
21
24
  import fcntl
25
+ import re
22
26
  import struct
27
+ import subprocess
23
28
  import array
24
29
  import struct
30
+ import tempfile
25
31
  import typing
26
32
  import os
33
+ import yaml
27
34
 
28
- # ethtool helper
29
- ETHTOOL_GDRVINFO = 0x00000003 # Get driver info
30
- STRUCT_DRVINFO = struct.Struct(
31
- "I" + # cmd
32
- "32s" + # driver
33
- "32s" + # version
34
- "32s" + # fw_version
35
- "32s" + # bus_info
36
- "32s" + # reserved1
37
- "12s" + # reserved2
38
- "I" + # n_priv_flags
39
- "I" + # n_stats
40
- "I" + # testinfo_len
41
- "I" + # eedump_len
42
- "I" # regdump_len
43
- )
44
-
45
- ETHTOOL_GPERMADDR = 0x00000020 # Get permanent hardware address
46
- L2_ADDRLENGTH = 6 # L2 address length
35
+ def _get_of_node(netns, link):
36
+ if netns.netns is not None:
37
+ pyroute2.netns.pushns(netns.netns)
38
+
39
+ try:
40
+ return os.path.relpath(os.path.realpath(f"{netns.ipr.sysfs_path}/class/net/{link.get_attr('IFLA_IFNAME')}/of_node", strict=True), start=f"{netns.ipr.sysfs_path}/firmware/devicetree")
41
+ except FileNotFoundError:
42
+ return None
43
+ finally:
44
+ if netns.netns is not None:
45
+ pyroute2.netns.popns()
46
+
47
+ IDENTIFY_LOOKUPS = {
48
+ "perm_address": lambda netns, link: link.get_attr("IFLA_PERM_ADDRESS"),
49
+ "parent_dev_name": lambda netns, link: link.get_attr("IFLA_PARENT_DEV_NAME"),
50
+ "parent_dev_bus_name": lambda netns, link: link.get_attr("IFLA_PARENT_DEV_BUS_NAME"),
51
+ "phys_port_id": lambda netns, link: link.get_attr("IFLA_PHYS_PORT_ID"),
52
+ "phys_port_name": lambda netns, link: link.get_attr("IFLA_PHYS_PORT_NAME"),
53
+ "phys_switch_id": lambda netns, link: link.get_attr("IFLA_PHYS_SWITCH_ID"),
54
+ "of_node": _get_of_node,
55
+ }
56
+
57
+
58
+ REGEX_ETHER_BYTE = re.compile('[a-f0-9]{2}')
59
+
60
+ RUN_BASE_DIR = '/run/libifstate'
47
61
 
48
62
  root_ipr = typing.NewType("IPRouteExt", IPRoute)
49
63
 
@@ -59,28 +73,103 @@ def filter_ifla_dump(showall, ifla, defaults, prefix="IFLA"):
59
73
 
60
74
  return dump
61
75
 
76
+ def format_ether_address(address):
77
+ """
78
+ Formats a ether address string canonical. Accepted formats:
79
+
80
+ xx:xx:xx:xx:xx:xx
81
+ xx-xx-xx-xx-xx-xx
82
+ xxxx.xxxx.xxxx
83
+
84
+ The hex digits may be lower and upper case.
85
+ """
86
+
87
+ return ':'.join(REGEX_ETHER_BYTE.findall(address.lower()))
88
+
89
+
90
+ def get_run_dir(function, *args):
91
+ """
92
+ Returns a deterministic directory under /run/libifstate for saving state
93
+ informations between ifstate calls. A hierarchy is build from the ifstate
94
+ function and additional distinguishers (i.e. ifname).
95
+
96
+ The directory will be created if it does not already exists.
97
+ """
98
+
99
+ run_dir = os.path.join(RUN_BASE_DIR, function, *args)
100
+
101
+ try:
102
+ os.makedirs(run_dir, mode=0o700)
103
+ except FileExistsError:
104
+ pass
105
+
106
+ return run_dir
107
+
108
+ def get_netns_run_dir(function, netns, *args):
109
+ """
110
+ Returns a deterministic directory under /run/libifstate for saving state
111
+ informations between ifstate calls. A hierarchy is build from the ifstate
112
+ function, the netns and optional additional distinguishers (i.e. ifname).
113
+
114
+ The directory will be created if it does not already exists.
115
+ """
116
+
117
+ if netns.netns is None:
118
+ run_dir = os.path.join(RUN_BASE_DIR, function, 'root', *args)
119
+ else:
120
+ run_dir = os.path.join(RUN_BASE_DIR, function, 'netns', netns.netns, *args)
121
+
122
+ try:
123
+ os.makedirs(run_dir, mode=0o700)
124
+ except FileExistsError:
125
+ pass
126
+
127
+ return run_dir
128
+
129
+ def dump_yaml_file(fn, obj, opener=None):
130
+ """
131
+ Dump obj to a YAML file, create directories if needed and catch file
132
+ I/O errors.
133
+ """
134
+ try:
135
+ os.makedirs(os.path.dirname(fn), mode=0o700)
136
+ except FileExistsError:
137
+ pass
138
+
139
+ try:
140
+ with open(fn, "w", opener=opener) as fh:
141
+ yaml.dump(obj, fh)
142
+ except OSError as err:
143
+ logger.error('Writing {} failed: {}'.format(fn, err))
144
+
145
+ def slurp_yaml_file(fn, default=None):
146
+ """
147
+ Read the content of a YAML file, returns *default* if the file could not be
148
+ found, read or parsed.
149
+ """
150
+ try:
151
+ with open(fn) as fh:
152
+ return yaml.load(fh, Loader=yaml.SafeLoader)
153
+ except OSError as err:
154
+ logger.debug('Reading {} failed: {}'.format(fn, err))
155
+ except yaml.YAMLError as err:
156
+ logger.warning('Parsing {} failed: {}'.format(fn, err))
157
+
158
+ return default
159
+
160
+ def kind_has_identify(kind):
161
+ """
162
+ Return True if the interface kind can be identified by some unique
163
+ properties. These are all types of physical interfaces.
164
+ """
165
+ return kind is None or kind in ['dsa']
166
+
62
167
  class IPRouteExt(IPRoute):
63
168
  def __init__(self, *args, **kwargs):
64
169
  super().__init__(*args, **kwargs)
65
170
 
66
171
  self.__sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
67
-
68
-
69
-
70
- # def fork_before():
71
- # import sys
72
- # print(f"FORK[{os.getpid()}] before", file=sys.stderr)
73
-
74
- # def fork_parent():
75
- # import sys
76
- # print(f"FORK[{os.getpid()}] parent", file=sys.stderr)
77
-
78
- # def fork_child():
79
- # import sys
80
- # print(f"FORK[{os.getpid()}] after", file=sys.stderr)
81
-
82
- # os.register_at_fork(before=fork_before, after_in_parent=fork_parent, after_in_child=fork_child)
83
-
172
+ self.sysfs_path = "/sys"
84
173
 
85
174
  def del_filter_by_info(self, index=0, handle=0, info=0, parent=0):
86
175
  msg = tcmsg()
@@ -97,60 +186,6 @@ class IPRouteExt(IPRoute):
97
186
  NLM_F_ACK
98
187
  ))
99
188
 
100
- def get_businfo(self, ifname):
101
- data = array.array("B", struct.pack(
102
- "I", ETHTOOL_GDRVINFO))
103
- data.extend(b'\x00' * (STRUCT_DRVINFO.size - len(data)))
104
-
105
- ifr = struct.pack('16sP', ifname.encode(
106
- "utf-8"), data.buffer_info()[0])
107
-
108
- try:
109
- r = fcntl.ioctl(self.__sock.fileno(), SIOCETHTOOL, ifr)
110
- except OSError:
111
- return None
112
-
113
- drvinfo = STRUCT_DRVINFO.unpack(data)
114
-
115
- return drvinfo[4].decode('ascii').split('\x00')[0]
116
-
117
- def get_permaddr(self, ifname):
118
- data = array.array("B", struct.pack(
119
- "II", ETHTOOL_GPERMADDR, L2_ADDRLENGTH))
120
- data.extend(b'\x00' * L2_ADDRLENGTH)
121
-
122
- ifr = struct.pack('16sP', ifname.encode(
123
- "utf-8"), data.buffer_info()[0])
124
-
125
- try:
126
- r = fcntl.ioctl(self.__sock.fileno(), SIOCETHTOOL, ifr)
127
- except OSError:
128
- return None
129
-
130
- l2addr = ":".join(format(x, "02x") for x in data[8:])
131
- if l2addr == "00:00:00:00:00:00":
132
- return None
133
-
134
- return l2addr
135
-
136
- def get_iface_by_businfo(self, businfo):
137
- for iface in iter(self.get_links()):
138
- ifname = iface.get_attr('IFLA_IFNAME')
139
- bi = self.get_businfo(ifname)
140
-
141
- if bi and bi == businfo:
142
- return iface['index']
143
-
144
- def get_iface_by_permaddr(self, permaddr):
145
- for iface in iter(self.get_links()):
146
- ifname = iface.get_attr('IFLA_IFNAME')
147
- addr = self.get_permaddr(ifname)
148
-
149
- if addr and addr == permaddr:
150
- return iface['index']
151
-
152
- return None
153
-
154
189
  def get_ifname_by_index(self, index):
155
190
  link = next(iter(self.get_links(index)), None)
156
191
 
@@ -207,10 +242,31 @@ class NetNSExt(NetNS):
207
242
  self.netns = self.status["netns"]
208
243
 
209
244
  try:
210
- netns.pushns(self.netns)
245
+ pyroute2.netns.pushns(self.netns)
211
246
  self.__sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
247
+
248
+ os.makedirs("/run/libifstate/sysfs", exist_ok=True)
249
+ self.sysfs_path = tempfile.mkdtemp(prefix=self.netns, dir="/run/libifstate/sysfs")
250
+ rc = subprocess.run(['mount', '', self.sysfs_path, '-t', 'sysfs', '-o', 'ro,nosuid,nodev,noexec,noatime'])
251
+ if rc.returncode != 0:
252
+ logger.warning("Could not mount netns sysfs: {rc.stderr}")
253
+ else:
254
+ logger.debug('mounted sysfs for {} at {}'.format(self.netns, self.sysfs_path), extra={'netns': self.netns})
255
+ atexit.register(self.umount_sysfs)
212
256
  finally:
213
- netns.popns()
257
+ pyroute2.netns.popns()
258
+
259
+ def umount_sysfs(self):
260
+ rc = subprocess.run(['umount', self.sysfs_path, '-t', 'sysfs'])
261
+ if rc.returncode != 0:
262
+ logger.warning("Could not umount netns sysfs: {rc.stderr}")
263
+ else:
264
+ logger.debug('umounted sysfs for {} at {}'.format(self.netns, self.sysfs_path), extra={'netns': self.netns})
265
+
266
+ try:
267
+ os.rmdir(self.sysfs_path)
268
+ except OSError:
269
+ pass
214
270
 
215
271
  def del_filter_by_info(self, index=0, handle=0, info=0, parent=0):
216
272
  msg = tcmsg()
@@ -227,60 +283,6 @@ class NetNSExt(NetNS):
227
283
  NLM_F_ACK
228
284
  ))
229
285
 
230
- def get_businfo(self, ifname):
231
- data = array.array("B", struct.pack(
232
- "I", ETHTOOL_GDRVINFO))
233
- data.extend(b'\x00' * (STRUCT_DRVINFO.size - len(data)))
234
-
235
- ifr = struct.pack('16sP', ifname.encode(
236
- "utf-8"), data.buffer_info()[0])
237
-
238
- try:
239
- r = fcntl.ioctl(self.__sock.fileno(), SIOCETHTOOL, ifr)
240
- except OSError:
241
- return None
242
-
243
- drvinfo = STRUCT_DRVINFO.unpack(data)
244
-
245
- return drvinfo[4].decode('ascii').split('\x00')[0]
246
-
247
- def get_permaddr(self, ifname):
248
- data = array.array("B", struct.pack(
249
- "II", ETHTOOL_GPERMADDR, L2_ADDRLENGTH))
250
- data.extend(b'\x00' * L2_ADDRLENGTH)
251
-
252
- ifr = struct.pack('16sP', ifname.encode(
253
- "utf-8"), data.buffer_info()[0])
254
-
255
- try:
256
- r = fcntl.ioctl(self.__sock.fileno(), SIOCETHTOOL, ifr)
257
- except OSError:
258
- return None
259
-
260
- l2addr = ":".join(format(x, "02x") for x in data[8:])
261
- if l2addr == "00:00:00:00:00:00":
262
- return None
263
-
264
- return l2addr
265
-
266
- def get_iface_by_businfo(self, businfo):
267
- for iface in iter(self.get_links()):
268
- ifname = iface.get_attr('IFLA_IFNAME')
269
- bi = self.get_businfo(ifname)
270
-
271
- if bi and bi == businfo:
272
- return iface['index']
273
-
274
- def get_iface_by_permaddr(self, permaddr):
275
- for iface in iter(self.get_links()):
276
- ifname = iface.get_attr('IFLA_IFNAME')
277
- addr = self.get_permaddr(ifname)
278
-
279
- if addr and addr == permaddr:
280
- return iface['index']
281
-
282
- return None
283
-
284
286
  def get_ifname_by_index(self, index):
285
287
  link = next(iter(self.get_links(index)), None)
286
288
 
@@ -369,3 +371,7 @@ class LinkDependency:
369
371
 
370
372
 
371
373
  root_ipr = IPRouteExt()
374
+ try:
375
+ root_iw = IW()
376
+ except NetlinkError:
377
+ root_iw = None
@@ -1,12 +1,16 @@
1
1
  from libifstate.util import logger, IfStateLogging
2
2
  from libifstate.exception import netlinkerror_classes, FeatureMissingError
3
- from wgnlpy import WireGuard as WG
4
- from ipaddress import ip_network
3
+ import wgnlpy
4
+ import ipaddress
5
5
  import collections
6
6
  from copy import deepcopy
7
+ import os
7
8
  import pyroute2.netns
9
+ from pyroute2 import NetlinkError
8
10
  import socket
9
11
 
12
+ SECRET_SETTINGS = ['private_key', 'preshared_key']
13
+
10
14
  class WireGuard():
11
15
  def __init__(self, netns, iface, wireguard):
12
16
  self.netns = netns
@@ -17,7 +21,7 @@ class WireGuard():
17
21
  pyroute2.netns.pushns(self.netns.netns)
18
22
 
19
23
  try:
20
- self.wg = WG()
24
+ self.wg = wgnlpy.WireGuard()
21
25
  finally:
22
26
  if self.netns.netns is not None:
23
27
  pyroute2.netns.popns()
@@ -28,7 +32,7 @@ class WireGuard():
28
32
  for i, peer in enumerate(self.wireguard['peers']):
29
33
  if 'allowedips' in peer:
30
34
  self.wireguard['peers'][i]['allowedips'] = set(
31
- [ip_network(x) for x in self.wireguard['peers'][i]['allowedips']])
35
+ [ipaddress.ip_network(x) for x in self.wireguard['peers'][i]['allowedips']])
32
36
 
33
37
  def __deepcopy__(self, memo):
34
38
  '''
@@ -43,7 +47,7 @@ class WireGuard():
43
47
  pyroute2.netns.pushns(self.netns.netns)
44
48
 
45
49
  try:
46
- setattr(result, k, WG())
50
+ setattr(result, k, wgnlpy.WireGuard())
47
51
  finally:
48
52
  if self.netns.netns is not None:
49
53
  pyroute2.netns.popns()
@@ -56,6 +60,9 @@ class WireGuard():
56
60
  try:
57
61
  state = self.wg.get_interface(
58
62
  self.iface, spill_private_key=True, spill_preshared_keys=True)
63
+ except NetlinkError as err:
64
+ logger.warning('query wireguard details failed: {}'.format(os.strerror(err.code)), extra={'iface': self.iface, 'netns': self.netns})
65
+ return
59
66
  except TypeError as err:
60
67
  # wgnlpy 0.1.5 can triggger a TypeError exception
61
68
  # if the WGPEER_A_LAST_HANDSHAKE_TIME NLA does not
@@ -94,15 +101,15 @@ class WireGuard():
94
101
  has_pchanges = False
95
102
 
96
103
  avail = []
97
- for peer in self.wireguard['peers']:
98
- avail.append(peer['public_key'])
104
+ for public_key, opts in self.wireguard['peers'].items():
105
+ avail.append(public_key)
99
106
  pubkey = next(
100
- iter([x for x in peers.keys() if x == peer['public_key']]), None)
107
+ iter([x for x in peers.keys() if x == public_key]), None)
101
108
  if pubkey is None:
102
109
  has_pchanges = True
103
110
  if do_apply:
104
111
  try:
105
- self.safe_set_peer(peer)
112
+ self.safe_set_peer(public_key, opts)
106
113
  except Exception as err:
107
114
  if not isinstance(err, netlinkerror_classes):
108
115
  raise
@@ -110,23 +117,23 @@ class WireGuard():
110
117
  self.iface, err.args[1]))
111
118
  else:
112
119
  pchange = False
113
- for setting in peer.keys():
120
+ for setting in opts.keys():
114
121
  attr = getattr(peers[pubkey], setting)
115
122
  if setting == 'allowedips':
116
- attr = set(attr)
123
+ attr = [str(ip) for ip in attr]
117
124
  logger.debug(' peer.%s: %s => %s', setting, attr,
118
- peer[setting], extra={'iface': self.iface})
119
- if type(attr) == set:
120
- pchange |= not (attr == peer[setting])
125
+ opts[setting], extra={'iface': self.iface})
126
+ if type(attr) == list:
127
+ pchange |= not (attr == opts[setting])
121
128
  else:
122
- pchange |= str(peer[setting]) != str(getattr(
129
+ pchange |= str(opts[setting]) != str(getattr(
123
130
  peers[pubkey], setting))
124
131
 
125
132
  if pchange:
126
133
  has_pchanges = True
127
134
  if do_apply:
128
135
  try:
129
- self.safe_set_peer(peer)
136
+ self.safe_set_peer(public_key, opts)
130
137
  except Exception as err:
131
138
  if not isinstance(err, netlinkerror_classes):
132
139
  raise
@@ -149,11 +156,65 @@ class WireGuard():
149
156
  else:
150
157
  logger.log_ok('wg.peers')
151
158
 
152
- def safe_set_peer(self, peer):
159
+ def safe_set_peer(self, public_key, opts):
153
160
  try:
154
- self.wg.set_peer(self.iface, **peer)
161
+ self.wg.set_peer(self.iface, public_key=public_key, **opts)
155
162
  except (socket.gaierror, ValueError) as err:
156
- logger.warning('failed to set wireguard endpoint at {}: {}'.format(self.iface, err))
163
+ logger.warning('failed to set wireguard endpoint for peer {} at {}: {}'.format(public_key, self.iface, err))
164
+
165
+ del(opts['endpoint'])
166
+ self.wg.set_peer(self.iface, public_key=public_key, **opts)
167
+
168
+ def show(netns, show_all, show_secrets, name, config):
169
+ if netns.netns is not None:
170
+ pyroute2.netns.pushns(self.netns.netns)
171
+
172
+ try:
173
+ wg = wgnlpy.WireGuard()
174
+ finally:
175
+ if netns.netns is not None:
176
+ pyroute2.netns.popns()
177
+
178
+ state = wg.get_interface(
179
+ name, spill_private_key=show_secrets, spill_preshared_keys=show_secrets)
180
+
181
+ config['wireguard'] = {
182
+ 'peers': {},
183
+ }
184
+
185
+ def _dump_value(value):
186
+ if isinstance(value, (ipaddress.IPv4Network, ipaddress.IPv6Network, wgnlpy.sockaddr_in.sockaddr_in)):
187
+ return str(value)
188
+ elif type(value) is list:
189
+ result = []
190
+ for v in value:
191
+ result.append(_dump_value(v))
192
+ return result
193
+ else:
194
+ return value
195
+
196
+ def _dump_values(cfg, key, value):
197
+ if show_all:
198
+ if value is None:
199
+ return
200
+ else:
201
+ if not value:
202
+ return
203
+
204
+ if key in SECRET_SETTINGS:
205
+ if show_secrets:
206
+ cfg[key] = str(value)
207
+ else:
208
+ cfg[key] = f"# VALUE IS HIDDEN - USE --show-secrets TO REVEAL"
209
+ else:
210
+ cfg[key] = _dump_value(value)
211
+
212
+ for key in ['private_key', 'listen_port', 'fwmark']:
213
+ value = getattr(state, key)
214
+ _dump_values(config['wireguard'], key, value)
157
215
 
158
- del(peer['endpoint'])
159
- self.wg.set_peer(self.iface, **peer)
216
+ for peer in state.peers:
217
+ config['wireguard']['peers'][str(peer)] = {}
218
+ for key in ['preshared_key', 'endpoint', 'persistent_keepalive_interval', 'allowedips']:
219
+ value = getattr(state.peers[peer], key)
220
+ _dump_values(config['wireguard']['peers'][str(peer)], key, value)
@@ -1,37 +0,0 @@
1
- ifstate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- ifstate/ifstate.py,sha256=l6VxiAXWyoqj7T5J495gM5Nhn807f5pHmL8_kh1uJAc,8891
3
- ifstate/shell.py,sha256=7_JFpi4icr9MijynDzbb0v5mxhFsng6PCC4m3uQ255A,2177
4
- ifstate/vrrp.py,sha256=cXzQZ2v-QS56ZBS8raLM4GyCjPFtTV6tg_9Drkgul1k,5952
5
- ifstate-1.13.6.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
6
- libifstate/__init__.py,sha256=SgY_-99Mn-OJzZsU1B1KEhfQI4EKa7dk0QxMLsGCKTc,30950
7
- libifstate/exception.py,sha256=5i59BZdl56J_sNJbyU9n6uHuUNJEyDOO4FJ-neDn9Ds,2608
8
- libifstate/log.py,sha256=XVoZdwdQoWsjuupFIuG6OP0OrBpXpx7oqyAaUhQ-nJk,4553
9
- libifstate/util.py,sha256=WzbGKX78iWUunnZ-v_3OREmxMiYt7vVM_QyCgTcMYow,10802
10
- libifstate/address/__init__.py,sha256=zIGM7UWXSvoijHMD06DfS2CDtiHpiJlqDgJG7Dl1IPE,3222
11
- libifstate/bpf/__init__.py,sha256=NVzaunTmJU2PbIQg9eWBMKpFgLh3EnD3ujNa7Yt6rNc,7699
12
- libifstate/bpf/ctypes.py,sha256=kLZJHZlba09Vc-tbsJAcKpDwdoNO2IjlYVLCopawHmA,4274
13
- libifstate/bpf/map.py,sha256=cLHNMvRBDNW2yVCEf3z242_oRdU0HqVbFEYVkKXng0w,10818
14
- libifstate/brport/__init__.py,sha256=NzdA8F4hr2se1bXKNnyKZbvOFlCWBq_cdjwsL1H0Y-o,2964
15
- libifstate/fdb/__init__.py,sha256=9dpL5n8ct3CaA-z8I6ZEkD3yL6yWJQeq3fpIe9pc2zw,6486
16
- libifstate/link/__init__.py,sha256=epVw6jY8exNeJZUmmUas91yJoeupfgIY7rthq7SGIIw,142
17
- libifstate/link/base.py,sha256=Si31tqRTRGnHusn1hRPLrfdEmeQqRyNP4aua1DlGc_Q,34319
18
- libifstate/link/dsa.py,sha256=Y3axTtcym6YL1voKblxctx4PoKDZHzpteKQNnEBUrS8,264
19
- libifstate/link/physical.py,sha256=cJiq-MCfy-3XQoU-OxzgfPZZtu_pJ8u2ioJgn9VYdGk,560
20
- libifstate/link/tun.py,sha256=m55o5cwO3h3DCLofUR-68fM4ggLoTKElp6ZJ2LrJSCc,959
21
- libifstate/link/veth.py,sha256=V_jmQCizI5Vv8-pcsfldSfMRTn1knR11wZDZI_yXvks,2249
22
- libifstate/neighbour/__init__.py,sha256=FJJpbJvqnxvOEii6QDMYzW5jQDEbiEy71GQOEbqaS48,2463
23
- libifstate/netns/__init__.py,sha256=oqUqU22C6RVMDwlgLccntQ3icenf9hiDs2FIWJIgny0,8772
24
- libifstate/parser/__init__.py,sha256=byz1W0G7UewVc5FFie-ti3UZjGK3-75wHIaOeq0oySQ,88
25
- libifstate/parser/base.py,sha256=VFAo05O3tiKtI381LVUMYfsDTseMKoQGTfkgnEkm3H4,4770
26
- libifstate/parser/yaml.py,sha256=MC0kmwqt3P45z61fb_wfUqoj0iZyhFYkdPyr0UqMSZA,1415
27
- libifstate/routing/__init__.py,sha256=Hmj-LHBEtVXs5tlRzY8JS_C5qdnN3alD3cIznmzQ-rY,20469
28
- libifstate/sysctl/__init__.py,sha256=EF52CdOOkVSUFR2t21A99KlG1-PjsD4qOiceQC4eI24,3074
29
- libifstate/tc/__init__.py,sha256=inPdampCOIr_4oKNB3awqMkW0Eh4fpPh9jvSba6sPVg,12092
30
- libifstate/wireguard/__init__.py,sha256=HEmGsrtIX8MEjxtMbqgzP-e2BIUicyfmcywnRE93lRQ,6579
31
- libifstate/xdp/__init__.py,sha256=X1xhEIGng7R5d5F4KsChykT2g6H-XBRWbWABijoYDQA,7208
32
- schema/ifstate.conf.schema.json,sha256=NOPeI8_r1jXvgAAJeBqz92ZACNvxskId3qMykj-sG7M,201292
33
- ifstate-1.13.6.dist-info/METADATA,sha256=uB4WuIOTixV34kGTfJVlhRSQv0j5bRm6lz4J04-aT0E,1598
34
- ifstate-1.13.6.dist-info/WHEEL,sha256=wXxTzcEDnjrTwFYjLPcsW_7_XihufBwmpiBeiXNBGEA,91
35
- ifstate-1.13.6.dist-info/entry_points.txt,sha256=HF6jX7Uu_nF1Ly-J9uEPeiRapOxnM6LuHsb2y6Mt-k4,52
36
- ifstate-1.13.6.dist-info/top_level.txt,sha256=A7peI7aKBaM69fsiSPvMbL3rzTKZZr5qDxKC-pHMGdE,19
37
- ifstate-1.13.6.dist-info/RECORD,,