ifstate 1.9.0__py3-none-any.whl → 1.10.1__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.
@@ -6,10 +6,16 @@ import logging
6
6
  import pyroute2
7
7
  import re
8
8
  import secrets
9
+ import shutil
10
+ import subprocess
9
11
 
10
12
  netns_name_map = {}
11
13
  netns_name_root = None
12
14
  netns_nsid_map = {}
15
+ findmnt_cmd = shutil.which('findmnt')
16
+
17
+ if findmnt_cmd is None:
18
+ logger.debug("findmnt binary is not available, netns binding of links might not be correct")
13
19
 
14
20
  @atexit.register
15
21
  def close_netns():
@@ -25,6 +31,7 @@ class NetNameSpace():
25
31
  self.links = {}
26
32
  self.addresses = {}
27
33
  self.bpf_progs = None
34
+ self.fdb = {}
28
35
  self.neighbours = {}
29
36
  self.vrrp = {
30
37
  'links': [],
@@ -40,9 +47,14 @@ class NetNameSpace():
40
47
 
41
48
  if name is None:
42
49
  self.ipr = root_ipr
50
+ self.mount = b''
43
51
  else:
44
52
  self.ipr = NetNSExt(name)
45
53
  netns_name_map[name] = self.ipr
54
+ if findmnt_cmd is None:
55
+ self.mount = name.encode("utf-8")
56
+ else:
57
+ self.mount = subprocess.check_output([findmnt_cmd, '-f', '-J', "/run/netns/{}".format(name)])
46
58
 
47
59
  def get_netnsid(self, peer_netns_name):
48
60
  if peer_netns_name is None:
@@ -51,17 +63,17 @@ class NetNameSpace():
51
63
  else:
52
64
  peer_ipr = netns_name_map[peer_netns_name]
53
65
  peer_pid = peer_ipr.child
54
-
66
+
55
67
  result = self.ipr.get_netnsid(pid=peer_pid)
56
68
  if result['nsid'] == 4294967295:
57
69
  self.ipr.set_netnsid(pid=peer_pid)
58
70
  result = self.ipr.get_netnsid(pid=peer_pid)
59
-
71
+
60
72
  peer_nsid = result['nsid']
61
73
 
62
74
  return (peer_ipr, peer_nsid)
63
75
 
64
- def prepare_netns(do_apply, target_netns_list):
76
+ def prepare_netns(do_apply, target_netns_list, new_netns_list):
65
77
  logger.info("configure network namespaces...")
66
78
 
67
79
  # get mapping of netns names to lists of pids
@@ -84,7 +96,7 @@ def prepare_netns(do_apply, target_netns_list):
84
96
  pyroute2.netns.remove(name)
85
97
 
86
98
  # create missing netns
87
- elif name not in current_netns_list:
99
+ elif name not in current_netns_list or name in new_netns_list:
88
100
  logger.log_add(name)
89
101
 
90
102
  # log already existing namespaces
@@ -123,25 +135,33 @@ class LinkRegistry():
123
135
  self.ignores = ignores
124
136
 
125
137
  for namespace in namespaces:
126
- self._inventory_netns(namespace)
138
+ self.inventory_netns(namespace)
127
139
 
128
140
  if logger.getEffectiveLevel() <= logging.DEBUG:
129
141
  self.debug_dump()
130
142
 
143
+ def add_link(self, netns, link):
144
+ item = LinkRegistryItem(
145
+ self,
146
+ netns,
147
+ link,
148
+ )
149
+ self.registry.append(item)
150
+ return item
151
+
131
152
  def get_link(self, **attributes):
132
153
  for link in self.registry:
133
154
  if link.match(**attributes):
134
155
  return link
135
156
  return None
136
157
 
137
- def _inventory_netns(self, target_netns):
158
+ def inventory_netns(self, target_netns):
138
159
  for link in target_netns.ipr.get_links():
139
- if link['index'] > 1:
140
- self.registry.append(LinkRegistryItem(
141
- self,
142
- target_netns,
143
- link,
144
- ))
160
+ self.registry.append(LinkRegistryItem(
161
+ self,
162
+ target_netns,
163
+ link,
164
+ ))
145
165
 
146
166
  def get_random_name(self, prefix):
147
167
  hex_length = int((15-len(prefix))/2)
@@ -209,7 +229,8 @@ class LinkRegistryItem():
209
229
 
210
230
  idx = next(iter(netns.ipr.link_lookup(ifname=self.attributes['ifname'])), None)
211
231
  if idx is not None:
212
- self.update_name( self.link_registry.get_random_name('__netns__') )
232
+ # ToDo
233
+ self.update_ifname( self.link_registry.get_random_name('__netns__') )
213
234
 
214
235
  self.__ipr_link('set', index=self.attributes['index'], net_ns_fd=netns_name)
215
236
  self.netns = netns
libifstate/parser/base.py CHANGED
@@ -5,6 +5,18 @@ from copy import deepcopy
5
5
 
6
6
 
7
7
  class Parser(ABC):
8
+ _default_lo_link = {
9
+ 'name': 'lo',
10
+ 'addresses': [
11
+ '127.0.0.1/8',
12
+ '::1/128',
13
+ ],
14
+ 'link': {
15
+ 'kind': 'physical',
16
+ 'state': 'up',
17
+ 'mtu': 65536,
18
+ }
19
+ }
8
20
  _default_ifstates = {
9
21
  'ignore': {
10
22
  'ipaddr_builtin': [
@@ -14,12 +26,15 @@ class Parser(ABC):
14
26
  'ifname_builtin': [
15
27
  r'^br-[\da-f]{12}',
16
28
  r'^docker\d+',
17
- r'^lo$',
18
29
  r'^ppp\d+$',
19
30
  r'^veth',
20
31
  r'^virbr\d+',
21
32
  r'^vrrp\d*\.\d+$'
22
33
  ],
34
+ 'fdb_builtin': [
35
+ r'^33:33:',
36
+ r'^01:00:5e:'
37
+ ],
23
38
  'routes_builtin': [
24
39
  {'proto': 1},
25
40
  {'proto': 2},
@@ -97,6 +112,14 @@ class Parser(ABC):
97
112
  a[key] = b[key]
98
113
  return a
99
114
 
115
+ def _update_lo(self, cfg):
116
+ if 'interfaces' in cfg:
117
+ lo = next((idx for idx, iface in enumerate(cfg['interfaces']) if iface['name'] == 'lo'), None)
118
+ if lo is not None:
119
+ cfg['interfaces'][lo] = self.merge(deepcopy(Parser._default_lo_link), cfg['interfaces'][lo])
120
+ else:
121
+ cfg['interfaces'].append(Parser._default_lo_link)
122
+
100
123
  def config(self):
101
124
  # merge builtin defaults with config
102
125
  cfg = (self.merge(deepcopy(Parser._default_ifstates), self.ifstates))
@@ -107,6 +130,11 @@ class Parser(ABC):
107
130
  except TypeError:
108
131
  raise ParserValidationError("$.ignore: is not of type 'object'")
109
132
 
133
+ # add loopback interface defaults
134
+ self._update_lo(cfg)
135
+ for namespace in cfg.get('namespaces', {}):
136
+ self._update_lo(cfg['namespaces'][namespace])
137
+
110
138
  # merge builtin defaults
111
139
  for k in list(cfg["ignore"]):
112
140
  if k.endswith("_builtin"):
@@ -7,11 +7,15 @@ import os
7
7
  class Sysctl():
8
8
  def __init__(self, netns):
9
9
  self.sysctls = {}
10
+ self.globals = {}
10
11
  self.netns = netns
11
12
 
12
13
  def add(self, iface, sysctl):
13
14
  self.sysctls[iface] = sysctl
14
15
 
16
+ def add_global(self, proto, sysctl):
17
+ self.globals[proto] = sysctl
18
+
15
19
  def set_sysctl(self, iface_current, iface_config, family, key, val, do_apply):
16
20
  if self.netns.netns is not None:
17
21
  pyroute2.netns.pushns(self.netns.netns)
@@ -66,3 +70,14 @@ class Sysctl():
66
70
 
67
71
  def has_settings(self, iface):
68
72
  return iface in self.sysctls
73
+
74
+ def apply_globals(self, do_apply):
75
+ changes = []
76
+ for proto, sysctl in self.globals.items():
77
+ for key, val in sysctl.items():
78
+ if self.set_sysctl('..', '..', proto, key, val, do_apply):
79
+ changes.append(proto)
80
+ return changes
81
+
82
+ def has_globals(self):
83
+ return len(self.globals) > 0
libifstate/util.py CHANGED
@@ -2,7 +2,8 @@ from libifstate.log import logger, IfStateLogging
2
2
  from pyroute2 import IPRoute, NetNS, netns
3
3
 
4
4
  from pyroute2.netlink.rtnl.tcmsg import tcmsg
5
- from pyroute2.netlink.rtnl import RTM_DELTFILTER
5
+ from pyroute2.netlink.rtnl import RTM_DELTFILTER, RTM_NEWNSID
6
+ from pyroute2.netlink.rtnl.nsidmsg import nsidmsg
6
7
  from pyroute2.netlink import NLM_F_REQUEST
7
8
  from pyroute2.netlink import NLM_F_ACK
8
9
  from pyroute2.netlink import NLM_F_CREATE
@@ -132,13 +133,36 @@ class IPRouteExt(IPRoute):
132
133
  return None
133
134
 
134
135
  def get_ifname_by_index(self, index):
135
- link = next(iter(ipr.get_links(index)), None)
136
+ link = next(iter(self.get_links(index)), None)
136
137
 
137
138
  if link is None:
138
139
  return index
139
140
 
140
141
  return link.get_attr('IFLA_IFNAME')
141
142
 
143
+ def set_netnsid(self, nsid=None, pid=None, fd=None):
144
+ '''
145
+ call pyroute2's set_netnsid if available or use
146
+ fallback implementation for pyroute2 <=0.79
147
+ '''
148
+ if hasattr(super(), 'set_netnsid'):
149
+ return super().set_netnsid(nsid, pid, fd)
150
+ else:
151
+ msg = nsidmsg()
152
+
153
+ if nsid is None or nsid < 0:
154
+ # kernel auto select
155
+ msg['attrs'].append(('NETNSA_NSID', 4294967295))
156
+ else:
157
+ msg['attrs'].append(('NETNSA_NSID', nsid))
158
+
159
+ if pid is not None:
160
+ msg['attrs'].append(('NETNSA_PID', pid))
161
+
162
+ if fd is not None:
163
+ msg['attrs'].append(('NETNSA_FD', fd))
164
+
165
+ return self.nlm_request(msg, RTM_NEWNSID, NLM_F_REQUEST | NLM_F_ACK)
142
166
 
143
167
  class NetNSExt(NetNS):
144
168
  def __init__(self, *args, **kwargs):
@@ -220,13 +244,37 @@ class NetNSExt(NetNS):
220
244
  return None
221
245
 
222
246
  def get_ifname_by_index(self, index):
223
- link = next(iter(ipr.get_links(index)), None)
247
+ link = next(iter(self.get_links(index)), None)
224
248
 
225
249
  if link is None:
226
250
  return index
227
251
 
228
252
  return link.get_attr('IFLA_IFNAME')
229
253
 
254
+ def set_netnsid(self, nsid=None, pid=None, fd=None):
255
+ '''
256
+ call pyroute2's set_netnsid if available or use
257
+ fallback implementation for pyroute2 <=0.79
258
+ '''
259
+ if hasattr(super(), 'set_netnsid'):
260
+ return super().set_netnsid(nsid, pid, fd)
261
+ else:
262
+ msg = nsidmsg()
263
+
264
+ if nsid is None or nsid < 0:
265
+ # kernel auto select
266
+ msg['attrs'].append(('NETNSA_NSID', 4294967295))
267
+ else:
268
+ msg['attrs'].append(('NETNSA_NSID', nsid))
269
+
270
+ if pid is not None:
271
+ msg['attrs'].append(('NETNSA_PID', pid))
272
+
273
+ if fd is not None:
274
+ msg['attrs'].append(('NETNSA_FD', fd))
275
+
276
+ return self.nlm_request(msg, RTM_NEWNSID, NLM_F_REQUEST | NLM_F_ACK)
277
+
230
278
  class LinkDependency:
231
279
  def __init__(self, ifname, netns):
232
280
  self.ifname = ifname
@@ -240,14 +288,23 @@ class LinkDependency:
240
288
 
241
289
  def __lt__(self, obj):
242
290
  if self.netns is None:
243
- return True
244
-
245
- if obj.netns is None:
291
+ if obj.netns is not None:
292
+ return True
293
+ elif obj.netns is None:
246
294
  return False
247
295
 
248
296
  if self.netns != obj.netns:
249
297
  return self.netns < obj.netns
250
298
 
299
+ if self.ifname == obj.ifname:
300
+ return False
301
+
302
+ if self.ifname == 'lo':
303
+ return True
304
+
305
+ if obj.ifname == 'lo':
306
+ return False
307
+
251
308
  return self.ifname < obj.ifname
252
309
 
253
310
  def __ne__(self, other):