ifstate 1.13.7__py3-none-any.whl → 2.0.0rc1__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.
- hooks/wrapper.sh +50 -0
- ifstate/ifstate.py +7 -2
- {ifstate-1.13.7.dist-info → ifstate-2.0.0rc1.dist-info}/METADATA +1 -1
- ifstate-2.0.0rc1.dist-info/RECORD +38 -0
- libifstate/__init__.py +88 -38
- libifstate/hook/__init__.py +195 -0
- libifstate/link/__init__.py +0 -1
- libifstate/link/base.py +23 -31
- libifstate/link/physical.py +2 -2
- libifstate/link/tun.py +2 -2
- libifstate/link/veth.py +2 -2
- libifstate/netns/__init__.py +40 -5
- libifstate/parser/base.py +107 -84
- libifstate/routing/__init__.py +62 -16
- libifstate/util.py +146 -147
- libifstate/wireguard/__init__.py +16 -16
- schema/2/ifstate.conf.schema.json +4398 -0
- ifstate-1.13.7.dist-info/RECORD +0 -37
- libifstate/link/dsa.py +0 -10
- schema/ifstate.conf.schema.json +0 -4259
- {ifstate-1.13.7.dist-info → ifstate-2.0.0rc1.dist-info}/WHEEL +0 -0
- {ifstate-1.13.7.dist-info → ifstate-2.0.0rc1.dist-info}/entry_points.txt +0 -0
- {ifstate-1.13.7.dist-info → ifstate-2.0.0rc1.dist-info}/licenses/LICENSE +0 -0
- {ifstate-1.13.7.dist-info → ifstate-2.0.0rc1.dist-info}/top_level.txt +0 -0
libifstate/link/base.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from libifstate.util import logger, IfStateLogging, LinkDependency
|
1
|
+
from libifstate.util import logger, format_ether_address, IfStateLogging, LinkDependency, IDENTIFY_LOOKUPS
|
2
2
|
from libifstate.exception import ExceptionCollector, LinkTypeUnknown, NetnsUnknown, netlinkerror_classes
|
3
3
|
from libifstate.brport import BRPort
|
4
4
|
from libifstate.routing import RTLookups
|
@@ -129,7 +129,7 @@ class Link(ABC):
|
|
129
129
|
return super().__new__(GenericLink)
|
130
130
|
#raise LinkTypeUnknown()
|
131
131
|
|
132
|
-
def __init__(self, ifstate, netns, name, link, ethtool, vrrp, brport):
|
132
|
+
def __init__(self, ifstate, netns, name, link, identify, ethtool, hooks, vrrp, brport):
|
133
133
|
self.ifstate = ifstate
|
134
134
|
self.netns = netns
|
135
135
|
self.cap_create = True
|
@@ -139,6 +139,7 @@ class Link(ABC):
|
|
139
139
|
}
|
140
140
|
self.settings.update(link)
|
141
141
|
self.ethtool = None
|
142
|
+
self.hooks = hooks
|
142
143
|
self.vrrp = vrrp
|
143
144
|
if brport:
|
144
145
|
self.brport = BRPort(netns, name, brport)
|
@@ -154,22 +155,17 @@ class Link(ABC):
|
|
154
155
|
self.link_ref = LinkDependency(name, self.netns.netns)
|
155
156
|
|
156
157
|
# prepare link registry search filters
|
157
|
-
if
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
self.settings['permaddr'] = self.settings['permaddr'].lower()
|
166
|
-
self.link_registry_search_args.append({
|
167
|
-
'kind': self.settings['kind'],
|
168
|
-
'permaddr': self.settings['permaddr'],
|
169
|
-
})
|
158
|
+
if identify:
|
159
|
+
search_args = {}
|
160
|
+
for attr in IDENTIFY_LOOKUPS.keys():
|
161
|
+
if attr in identify:
|
162
|
+
search_args[attr] = identify[attr]
|
163
|
+
if search_args:
|
164
|
+
search_args['kind'] = self.settings['kind']
|
165
|
+
self.link_registry_search_args.append(search_args)
|
170
166
|
|
171
167
|
if 'address' in self.settings and self.settings['kind'] == 'physical':
|
172
|
-
self.settings['address'] = self.settings['address']
|
168
|
+
self.settings['address'] = format_ether_address(self.settings['address'])
|
173
169
|
self.link_registry_search_args.append({
|
174
170
|
'kind': self.settings['kind'],
|
175
171
|
'address': self.settings['address'],
|
@@ -249,11 +245,8 @@ class Link(ABC):
|
|
249
245
|
return None
|
250
246
|
|
251
247
|
def get_if_attr(self, key):
|
252
|
-
if key
|
253
|
-
|
254
|
-
return self.iface[key]
|
255
|
-
else:
|
256
|
-
return None
|
248
|
+
if key == "state":
|
249
|
+
return self.iface.get(key)
|
257
250
|
|
258
251
|
if key in self.attr_map:
|
259
252
|
return self._drill_attr(self.iface, self.attr_map[key])
|
@@ -522,13 +515,6 @@ class Link(ABC):
|
|
522
515
|
if self.idx is not None:
|
523
516
|
self.iface = item.netns.ipr.get_link(self.idx)
|
524
517
|
if self.idx is not None and self.iface is not None:
|
525
|
-
permaddr = item.netns.ipr.get_permaddr(self.iface.get_attr('IFLA_IFNAME'))
|
526
|
-
if not permaddr is None:
|
527
|
-
self.iface['permaddr'] = permaddr
|
528
|
-
businfo = item.netns.ipr.get_businfo(self.iface.get_attr('IFLA_IFNAME'))
|
529
|
-
if not businfo is None:
|
530
|
-
self.iface['businfo'] = businfo
|
531
|
-
|
532
518
|
# check for ifname collisions
|
533
519
|
idx = next(iter(self.netns.ipr.link_lookup(
|
534
520
|
ifname=self.settings['ifname'])), None)
|
@@ -631,6 +617,9 @@ class Link(ABC):
|
|
631
617
|
if not isinstance(err, netlinkerror_classes):
|
632
618
|
raise
|
633
619
|
excpts.add('set', err, state=state)
|
620
|
+
|
621
|
+
# get kernel state
|
622
|
+
self.iface = self.netns.ipr.get_link(self.idx)
|
634
623
|
except Exception as err:
|
635
624
|
if not isinstance(err, netlinkerror_classes):
|
636
625
|
raise
|
@@ -743,7 +732,7 @@ class Link(ABC):
|
|
743
732
|
if do_apply:
|
744
733
|
# temp. remove special settings
|
745
734
|
skipped_settings = {}
|
746
|
-
for setting in ['state', 'peer', 'kind'
|
735
|
+
for setting in ['state', 'peer', 'kind']:
|
747
736
|
if setting in self.settings:
|
748
737
|
skipped_settings[setting] = self.settings.pop(setting)
|
749
738
|
|
@@ -838,6 +827,9 @@ class Link(ABC):
|
|
838
827
|
else:
|
839
828
|
logger.log_ok('link')
|
840
829
|
|
830
|
+
# update kernel state
|
831
|
+
self.iface = self.netns.ipr.get_link(self.idx)
|
832
|
+
|
841
833
|
def depends(self):
|
842
834
|
deps = []
|
843
835
|
|
@@ -900,5 +892,5 @@ class Link(ABC):
|
|
900
892
|
|
901
893
|
|
902
894
|
class GenericLink(Link):
|
903
|
-
def __init__(self, ifstate, netns, name, link, ethtool, vrrp, brport):
|
904
|
-
super().__init__(ifstate, netns, name, link, ethtool, vrrp, brport)
|
895
|
+
def __init__(self, ifstate, netns, name, link, identify, ethtool, hooks, vrrp, brport):
|
896
|
+
super().__init__(ifstate, netns, name, link, identify, ethtool, hooks, vrrp, brport)
|
libifstate/link/physical.py
CHANGED
@@ -3,8 +3,8 @@ from libifstate.link.base import Link
|
|
3
3
|
from libifstate.exception import LinkCannotAdd
|
4
4
|
|
5
5
|
class PhysicalLink(Link):
|
6
|
-
def __init__(self, ifstate, netns, name, link, ethtool, vrrp, brport):
|
7
|
-
super().__init__(ifstate, netns, name, link, ethtool, vrrp, brport)
|
6
|
+
def __init__(self, ifstate, netns, name, link, identify, ethtool, hooks, vrrp, brport):
|
7
|
+
super().__init__(ifstate, netns, name, link, identify, ethtool, hooks, vrrp, brport)
|
8
8
|
self.cap_create = False
|
9
9
|
self.cap_ethtool = True
|
10
10
|
self.ethtool = ethtool
|
libifstate/link/tun.py
CHANGED
@@ -6,14 +6,14 @@ from pwd import getpwnam
|
|
6
6
|
from grp import getgrnam
|
7
7
|
|
8
8
|
class TunLink(Link):
|
9
|
-
def __init__(self, ifstate, netns, name, link, ethtool, vrrp, brport):
|
9
|
+
def __init__(self, ifstate, netns, name, link, identify, ethtool, hooks, vrrp, brport):
|
10
10
|
if 'tun_owner' in link and isinstance(link['tun_owner'], str):
|
11
11
|
link['tun_owner'] = getpwnam(link['tun_owner'])[2]
|
12
12
|
|
13
13
|
if 'tun_group' in link and isinstance(link['tun_group'], str):
|
14
14
|
link['tun_group'] = getgrnam(link['tun_group'])[2]
|
15
15
|
|
16
|
-
super().__init__(ifstate, netns, name, link, ethtool, vrrp, brport)
|
16
|
+
super().__init__(ifstate, netns, name, link, identify, ethtool, hooks, vrrp, brport)
|
17
17
|
self.cap_create = bool(link.get('tun_persist'))
|
18
18
|
|
19
19
|
def create(self, do_apply, sysctl, excpts, oper="add"):
|
libifstate/link/veth.py
CHANGED
@@ -3,14 +3,14 @@ from libifstate.link.base import Link
|
|
3
3
|
from libifstate.exception import LinkCannotAdd, NetnsUnknown
|
4
4
|
|
5
5
|
class VethLink(Link):
|
6
|
-
def __init__(self, ifstate, netns, name, link, ethtool, vrrp, brport):
|
6
|
+
def __init__(self, ifstate, netns, name, link, identify, ethtool, hooks, vrrp, brport):
|
7
7
|
# use the bind_netns implementation to create the peer in the
|
8
8
|
# target netns
|
9
9
|
if 'peer_netns' in link:
|
10
10
|
link['bind_netns'] = link['peer_netns']
|
11
11
|
del(link['peer_netns'])
|
12
12
|
|
13
|
-
super().__init__(ifstate, netns, name, link, ethtool, vrrp, brport)
|
13
|
+
super().__init__(ifstate, netns, name, link, identify, ethtool, hooks, vrrp, brport)
|
14
14
|
|
15
15
|
def create(self, do_apply, sysctl, excpts, oper="add"):
|
16
16
|
'''
|
libifstate/netns/__init__.py
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
from libifstate.util import logger, IfStateLogging, IPRouteExt, NetNSExt, root_ipr
|
1
|
+
from libifstate.util import logger, IfStateLogging, IPRouteExt, NetNSExt, root_ipr, root_iw, IDENTIFY_LOOKUPS
|
2
2
|
from libifstate.sysctl import Sysctl
|
3
3
|
|
4
4
|
import atexit
|
5
5
|
from copy import deepcopy
|
6
6
|
import logging
|
7
7
|
import pyroute2
|
8
|
+
from pyroute2.netlink.exceptions import NetlinkError
|
8
9
|
import re
|
9
10
|
import secrets
|
10
11
|
import shutil
|
@@ -13,6 +14,7 @@ import subprocess
|
|
13
14
|
netns_name_map = {}
|
14
15
|
netns_name_root = None
|
15
16
|
netns_nsid_map = {}
|
17
|
+
iw_ifindex_phy_map = {}
|
16
18
|
|
17
19
|
@atexit.register
|
18
20
|
def close_netns():
|
@@ -44,12 +46,27 @@ class NetNameSpace():
|
|
44
46
|
|
45
47
|
if name is None:
|
46
48
|
self.ipr = root_ipr
|
49
|
+
self.iw = root_iw
|
47
50
|
self.mount = b''
|
48
51
|
else:
|
49
52
|
self.ipr = NetNSExt(name)
|
50
53
|
netns_name_map[name] = self.ipr
|
54
|
+
|
55
|
+
# check for wireless phys
|
56
|
+
if root_iw:
|
57
|
+
pyroute2.netns.pushns(name)
|
58
|
+
self.iw = pyroute2.IW()
|
59
|
+
pyroute2.netns.popns()
|
60
|
+
else:
|
61
|
+
self.iw = None
|
62
|
+
|
51
63
|
self.mount = name.encode("utf-8")
|
52
64
|
|
65
|
+
if self.iw is not None:
|
66
|
+
for ifname, ifdict in self.iw.get_interfaces_dict().items():
|
67
|
+
# ifIndex => phyIndex
|
68
|
+
iw_ifindex_phy_map[ifdict[0]] = ifdict[3]
|
69
|
+
|
53
70
|
def __deepcopy__(self, memo):
|
54
71
|
'''
|
55
72
|
Add custom deepcopy implementation to keep single IPRoute and NetNS instances.
|
@@ -59,7 +76,10 @@ class NetNameSpace():
|
|
59
76
|
memo[id(self)] = result
|
60
77
|
for k, v in self.__dict__.items():
|
61
78
|
if k == 'ipr':
|
62
|
-
|
79
|
+
if self.netns is None:
|
80
|
+
setattr(result, k, IPRouteExt())
|
81
|
+
else:
|
82
|
+
setattr(result, k, NetNSExt(self.netns))
|
63
83
|
else:
|
64
84
|
setattr(result, k, deepcopy(v, memo))
|
65
85
|
return result
|
@@ -223,8 +243,16 @@ class LinkRegistryItem():
|
|
223
243
|
self.attributes['kind'] = linkinfo.get_attr('IFLA_INFO_KIND')
|
224
244
|
else:
|
225
245
|
self.attributes['kind'] = "physical"
|
226
|
-
|
227
|
-
|
246
|
+
|
247
|
+
# add iw phy for wireless interfaces
|
248
|
+
if link['index'] in iw_ifindex_phy_map:
|
249
|
+
self.attributes['wiphy'] = iw_ifindex_phy_map[link['index']]
|
250
|
+
|
251
|
+
# add identify attributes
|
252
|
+
for attr, lookup in IDENTIFY_LOOKUPS.items():
|
253
|
+
value = lookup(netns, link)
|
254
|
+
if value is not None:
|
255
|
+
self.attributes[attr] = value
|
228
256
|
|
229
257
|
def __ipr_link(self, command, **kwargs):
|
230
258
|
logger.debug("ip link set netns={} {}".format(
|
@@ -271,7 +299,14 @@ class LinkRegistryItem():
|
|
271
299
|
# ToDo
|
272
300
|
self.update_ifname( self.registry.get_random_name('__netns__') )
|
273
301
|
|
274
|
-
|
302
|
+
if self.attributes.get('wiphy') is not None:
|
303
|
+
# move phy instead of iface for wireless devices
|
304
|
+
if netns.netns is None:
|
305
|
+
self.netns.iw.set_wiphy_netns_by_pid(self.attributes['wiphy'], 1)
|
306
|
+
else:
|
307
|
+
self.netns.iw.set_wiphy_netns_by_pid(self.attributes['wiphy'], netns.ipr.child)
|
308
|
+
else:
|
309
|
+
self.__ipr_link('set', index=self.attributes['index'], net_ns_fd=netns_name)
|
275
310
|
self.netns = netns
|
276
311
|
self.attributes['index'] = next(iter(self.netns.ipr.link_lookup(ifname=self.attributes['ifname'])), None)
|
277
312
|
|
libifstate/parser/base.py
CHANGED
@@ -6,7 +6,6 @@ from copy import deepcopy
|
|
6
6
|
|
7
7
|
class Parser(ABC):
|
8
8
|
_default_lo_link = {
|
9
|
-
'name': 'lo',
|
10
9
|
'addresses': [
|
11
10
|
'127.0.0.1/8',
|
12
11
|
'::1/128',
|
@@ -18,79 +17,96 @@ class Parser(ABC):
|
|
18
17
|
}
|
19
18
|
}
|
20
19
|
_default_ifstates = {
|
21
|
-
'
|
22
|
-
'
|
23
|
-
'
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
'
|
39
|
-
{
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
{'proto': 42},
|
52
|
-
{'proto': 186},
|
53
|
-
{'proto': 187},
|
54
|
-
{'proto': 188},
|
55
|
-
{'proto': 189},
|
56
|
-
{'proto': 192},
|
57
|
-
{'to': 'ff00::/8'},
|
58
|
-
],
|
59
|
-
'rules_builtin': [
|
60
|
-
{'proto': 1},
|
61
|
-
{'proto': 2},
|
62
|
-
{'proto': 8},
|
63
|
-
{'proto': 9},
|
64
|
-
{'proto': 10},
|
65
|
-
{'proto': 11},
|
66
|
-
{'proto': 12},
|
67
|
-
{'proto': 13},
|
68
|
-
{'proto': 14},
|
69
|
-
{'proto': 15},
|
70
|
-
{'proto': 16},
|
71
|
-
{'proto': 18},
|
72
|
-
{'proto': 42},
|
73
|
-
{'proto': 186},
|
74
|
-
{'proto': 187},
|
75
|
-
{'proto': 188},
|
76
|
-
{'proto': 189},
|
77
|
-
{'proto': 192},
|
78
|
-
],
|
79
|
-
},
|
80
|
-
'cshaper': {
|
81
|
-
'default': {
|
82
|
-
'egress_qdisc': {
|
83
|
-
'kind': 'cake',
|
84
|
-
'handle': '1:',
|
85
|
-
},
|
86
|
-
'ingress_qdisc': {
|
87
|
-
'kind': 'cake',
|
88
|
-
'handle': '1:',
|
89
|
-
},
|
90
|
-
'ingress_ifname': {
|
91
|
-
'search': r'^\D{1,3}',
|
92
|
-
'replace': 'ifb',
|
20
|
+
'parameters': {
|
21
|
+
'cshaper': {
|
22
|
+
'default': {
|
23
|
+
'egress_qdisc': {
|
24
|
+
'kind': 'cake',
|
25
|
+
'handle': '1:',
|
26
|
+
},
|
27
|
+
'ingress_qdisc': {
|
28
|
+
'kind': 'cake',
|
29
|
+
'handle': '1:',
|
30
|
+
},
|
31
|
+
'ingress_ifname': {
|
32
|
+
'search': r'^\D{1,3}',
|
33
|
+
'replace': 'ifb',
|
34
|
+
}
|
35
|
+
}
|
36
|
+
},
|
37
|
+
'defaults_builtin': [
|
38
|
+
{
|
39
|
+
'match': [
|
40
|
+
{'ifname': ''}
|
41
|
+
],
|
42
|
+
'clear_addresses': True,
|
43
|
+
'clear_fdb': True,
|
44
|
+
'clear_neighbours': True,
|
45
|
+
'clear_tc': True,
|
46
|
+
'link': {
|
47
|
+
'state': 'down',
|
48
|
+
'master': None
|
49
|
+
}
|
93
50
|
}
|
51
|
+
],
|
52
|
+
'ignore': {
|
53
|
+
'ipaddr_builtin': [
|
54
|
+
'fe80::/10'
|
55
|
+
],
|
56
|
+
'ipaddr_dynamic': True,
|
57
|
+
'ifname_builtin': [
|
58
|
+
r'^br-[\da-f]{12}',
|
59
|
+
r'^docker\d+',
|
60
|
+
r'^ppp\d+$',
|
61
|
+
r'^veth',
|
62
|
+
r'^virbr\d+',
|
63
|
+
r'^vrrp\d*\.\d+$'
|
64
|
+
],
|
65
|
+
'fdb_builtin': [
|
66
|
+
r'^33:33:',
|
67
|
+
r'^01:00:5e:'
|
68
|
+
],
|
69
|
+
'routes_builtin': [
|
70
|
+
{'proto': 1},
|
71
|
+
{'proto': 2},
|
72
|
+
{'proto': 8},
|
73
|
+
{'proto': 9},
|
74
|
+
{'proto': 10},
|
75
|
+
{'proto': 11},
|
76
|
+
{'proto': 12},
|
77
|
+
{'proto': 13},
|
78
|
+
{'proto': 14},
|
79
|
+
{'proto': 15},
|
80
|
+
{'proto': 16},
|
81
|
+
{'proto': 18},
|
82
|
+
{'proto': 42},
|
83
|
+
{'proto': 186},
|
84
|
+
{'proto': 187},
|
85
|
+
{'proto': 188},
|
86
|
+
{'proto': 189},
|
87
|
+
{'proto': 192},
|
88
|
+
{'to': 'ff00::/8'},
|
89
|
+
],
|
90
|
+
'rules_builtin': [
|
91
|
+
{'proto': 1},
|
92
|
+
{'proto': 2},
|
93
|
+
{'proto': 8},
|
94
|
+
{'proto': 9},
|
95
|
+
{'proto': 10},
|
96
|
+
{'proto': 11},
|
97
|
+
{'proto': 12},
|
98
|
+
{'proto': 13},
|
99
|
+
{'proto': 14},
|
100
|
+
{'proto': 15},
|
101
|
+
{'proto': 16},
|
102
|
+
{'proto': 18},
|
103
|
+
{'proto': 42},
|
104
|
+
{'proto': 186},
|
105
|
+
{'proto': 187},
|
106
|
+
{'proto': 188},
|
107
|
+
{'proto': 189},
|
108
|
+
{'proto': 192},
|
109
|
+
],
|
94
110
|
}
|
95
111
|
}
|
96
112
|
}
|
@@ -114,11 +130,11 @@ class Parser(ABC):
|
|
114
130
|
|
115
131
|
def _update_lo(self, cfg):
|
116
132
|
if 'interfaces' in cfg:
|
117
|
-
lo
|
118
|
-
|
119
|
-
|
133
|
+
if 'lo' in cfg['interfaces']:
|
134
|
+
cfg['interfaces']['lo'] = self.merge(
|
135
|
+
deepcopy(Parser._default_lo_link), cfg['interfaces']['lo'])
|
120
136
|
else:
|
121
|
-
cfg['interfaces']
|
137
|
+
cfg['interfaces']['lo'] = Parser._default_lo_link
|
122
138
|
|
123
139
|
def config(self):
|
124
140
|
# merge builtin defaults with config
|
@@ -126,7 +142,7 @@ class Parser(ABC):
|
|
126
142
|
|
127
143
|
# 'ignore' should still be an object
|
128
144
|
try:
|
129
|
-
iter(cfg["ignore"])
|
145
|
+
iter(cfg["parameters"]["ignore"])
|
130
146
|
except TypeError:
|
131
147
|
raise ParserValidationError("$.ignore: is not of type 'object'")
|
132
148
|
|
@@ -136,18 +152,25 @@ class Parser(ABC):
|
|
136
152
|
self._update_lo(cfg['namespaces'][namespace])
|
137
153
|
|
138
154
|
# merge builtin defaults
|
139
|
-
|
155
|
+
if "defaults" in cfg["parameters"]:
|
156
|
+
cfg["parameters"]["defaults"].extend(cfg["parameters"]["defaults_builtin"])
|
157
|
+
else:
|
158
|
+
cfg["parameters"]["defaults"] = cfg["parameters"]["defaults_builtin"]
|
159
|
+
del cfg["parameters"]["defaults_builtin"]
|
160
|
+
|
161
|
+
# merge builtin ignore lists
|
162
|
+
for k in list(cfg["parameters"]["ignore"]):
|
140
163
|
if k.endswith("_builtin"):
|
141
164
|
n = k[:-8]
|
142
|
-
if n in cfg["ignore"]:
|
165
|
+
if n in cfg["parameters"]["ignore"]:
|
143
166
|
try:
|
144
|
-
cfg["ignore"][n] += cfg["ignore"][k]
|
167
|
+
cfg["parameters"]["ignore"][n] += cfg["parameters"]["ignore"][k]
|
145
168
|
except TypeError:
|
146
169
|
raise ParserValidationError("$.ignore.{}: is not of type '{}'".format(
|
147
|
-
n, type(cfg["ignore"][k]).__name__))
|
170
|
+
n, type(cfg["parameters"]["ignore"][k]).__name__))
|
148
171
|
else:
|
149
|
-
cfg["ignore"][n] = cfg["ignore"][k]
|
150
|
-
del(cfg["ignore"][k])
|
172
|
+
cfg["parameters"]["ignore"][n] = cfg["parameters"]["ignore"][k]
|
173
|
+
del (cfg["parameters"]["ignore"][k])
|
151
174
|
|
152
175
|
return cfg
|
153
176
|
|
libifstate/routing/__init__.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
from libifstate.util import logger, IfStateLogging
|
2
2
|
from libifstate.exception import RouteDuplicate, netlinkerror_classes
|
3
|
-
from ipaddress import ip_address, ip_network, IPv6Network
|
3
|
+
from ipaddress import ip_address, ip_interface, ip_network, IPv6Network
|
4
4
|
from pyroute2.netlink.rtnl.fibmsg import FR_ACT_VALUES
|
5
5
|
from pyroute2.netlink.rtnl import rt_type
|
6
6
|
import collections.abc
|
@@ -284,8 +284,8 @@ class Tables(collections.abc.Mapping):
|
|
284
284
|
idx = next(
|
285
285
|
iter(self.netns.ipr.link_lookup(ifname=ignore[attr])), None)
|
286
286
|
if idx is None:
|
287
|
-
logger.debug("{} '{}' is unknown".format(attr, ignore[attr]))
|
288
|
-
|
287
|
+
logger.debug("{} '{}' is unknown, skipping ignore".format(attr, ignore[attr]))
|
288
|
+
continue
|
289
289
|
else:
|
290
290
|
ignore[attr] = idx
|
291
291
|
parsed.append(ignore)
|
@@ -321,7 +321,7 @@ class Tables(collections.abc.Mapping):
|
|
321
321
|
continue
|
322
322
|
|
323
323
|
if route['dst_len'] > 0:
|
324
|
-
dst =
|
324
|
+
dst = ip_interface(
|
325
325
|
'{}/{}'.format(route.get_attr('RTA_DST'), route['dst_len'])).with_prefixlen
|
326
326
|
elif route['family'] == AF_INET:
|
327
327
|
dst = ip_network('0.0.0.0/0').with_prefixlen
|
@@ -546,13 +546,18 @@ class Rules():
|
|
546
546
|
'tos': rule['tos'],
|
547
547
|
}
|
548
548
|
|
549
|
-
if
|
550
|
-
|
551
|
-
|
549
|
+
# add source and destination ip spaces even if they are not given by pyroute2
|
550
|
+
# as the user might specify something like "from: ::/0" explicitly which would not
|
551
|
+
# be present on a krule (because default values are ommited by pyroute2) and therefore
|
552
|
+
# would not match, even though it is the same rule
|
553
|
+
# if the user doesn't specify 'from' or 'to', these fields are just ignored because
|
554
|
+
# rule_matches is instructed to only check fields that are present on the config rule,
|
555
|
+
# meaning that these just get ignored
|
556
|
+
ru['dst'] = rule.get_attr('FRA_DST', default=("::" if rule['family'] == AF_INET6 else "0.0.0.0"))
|
557
|
+
ru['dst_len'] = rule['dst_len']
|
552
558
|
|
553
|
-
if rule['
|
554
|
-
|
555
|
-
ru['src_len'] = rule['src_len']
|
559
|
+
ru['src'] = rule.get_attr('FRA_SRC', default=("::" if rule['family'] == AF_INET6 else "0.0.0.0"))
|
560
|
+
ru['src_len'] = rule['src_len']
|
556
561
|
|
557
562
|
for field in ['iifname', 'oifname', 'fwmark', 'ip_proto']:
|
558
563
|
value = rule.get_attr('FRA_{}'.format(field.upper()))
|
@@ -593,7 +598,7 @@ class Rules():
|
|
593
598
|
del rule['protocol']
|
594
599
|
|
595
600
|
if 'src_len' in rule and rule['src_len'] > 0:
|
596
|
-
rule['from'] =
|
601
|
+
rule['from'] = ip_interface(
|
597
602
|
'{}/{}'.format(rule['src'], rule['src_len'])).with_prefixlen
|
598
603
|
|
599
604
|
for key in ['src', 'src_len', 'tos', 'protocol']:
|
@@ -609,32 +614,51 @@ class Rules():
|
|
609
614
|
|
610
615
|
# get rules that are currently in the kernels list
|
611
616
|
krules = self.kernel_rules()
|
617
|
+
|
618
|
+
# loop over all rules that are wanted by the config
|
612
619
|
for rule in self.rules:
|
613
620
|
log_str = '#{}'.format(rule['priority'])
|
621
|
+
|
622
|
+
if rule.get('family', None) == AF_INET6:
|
623
|
+
log_str += " (inet6)"
|
624
|
+
elif rule.get('family', None) == AF_INET:
|
625
|
+
log_str += " (inet)"
|
626
|
+
|
614
627
|
if self.netns.netns != None:
|
615
628
|
log_str += "[netns={}]".format(self.netns.netns)
|
616
629
|
|
630
|
+
vrrp_matched = vrrp_match(rule, by_vrrp, vrrp_type, vrrp_name, vrrp_state)
|
631
|
+
# 'found' indicates whether the rule wanted by the config was found
|
632
|
+
# in the kernels rules. if not, it is going to be added below
|
617
633
|
found = False
|
618
|
-
matched = vrrp_match(rule, by_vrrp, vrrp_type, vrrp_name, vrrp_state)
|
619
634
|
for i, krule in enumerate(krules):
|
620
635
|
if rule_matches(
|
621
636
|
rule,
|
622
637
|
krule,
|
623
638
|
# skip helper attrs like _vrrp
|
639
|
+
# note that rule_matches it told to only check fields that are
|
640
|
+
# present on the config rule, so additional ones from the krule
|
641
|
+
# just get ignored
|
624
642
|
[key for key in rule.keys() if key[0] != '_']
|
625
643
|
):
|
626
644
|
found = True
|
627
645
|
|
628
|
-
#
|
629
|
-
|
646
|
+
# we've just confirmed that this krule matches a rule
|
647
|
+
# that is wanted by the config so we delete it from the
|
648
|
+
# krules because any that remain in krule are unwanted
|
649
|
+
# and get deleted below
|
650
|
+
# EXCEPT if vrrp tells us to leave it be
|
651
|
+
if vrrp_matched != VRRP_MATCH_DISABLE:
|
630
652
|
del krules[i]
|
631
653
|
|
632
654
|
break
|
633
655
|
|
634
|
-
if
|
656
|
+
if vrrp_matched not in [VRRP_MATCH_IGNORE, VRRP_MATCH_DISABLE]:
|
635
657
|
if found:
|
658
|
+
# rule already exists
|
636
659
|
logger.log_ok(log_str)
|
637
660
|
else:
|
661
|
+
# rule doesn't exist, add it
|
638
662
|
logger.log_add(log_str)
|
639
663
|
|
640
664
|
logger.debug("ip rule add: {}".format(
|
@@ -647,7 +671,12 @@ class Rules():
|
|
647
671
|
raise
|
648
672
|
logger.warning('rule setup failed: {}'.format(err.args[1]))
|
649
673
|
|
674
|
+
# at this point all wanted rules have been deleted from the krules list,
|
675
|
+
# leaving the rest to be deleted here (see 'del krules[i]' above)
|
650
676
|
for rule in krules:
|
677
|
+
|
678
|
+
# if this rule falls into the ignored ones (like the ones set by the kernel itself by default)
|
679
|
+
# we will ignore it and continue
|
651
680
|
ignore = False
|
652
681
|
for irule in ignores:
|
653
682
|
if 'proto' in irule:
|
@@ -659,9 +688,26 @@ class Rules():
|
|
659
688
|
if ignore:
|
660
689
|
continue
|
661
690
|
|
662
|
-
|
691
|
+
log_str = '#{}'.format(rule['priority'])
|
692
|
+
|
693
|
+
if rule.get('family', None) == AF_INET6:
|
694
|
+
log_str += " (inet6)"
|
695
|
+
elif rule.get('family', None) == AF_INET:
|
696
|
+
log_str += " (inet)"
|
697
|
+
|
698
|
+
logger.log_del(log_str)
|
699
|
+
|
663
700
|
try:
|
664
701
|
if do_apply:
|
702
|
+
# for some reason pyroute2 raises an exception when
|
703
|
+
# we pass an address like "0.0.0.0" or "::" with an
|
704
|
+
# 'src_len' or 'dst_len' of 0.
|
705
|
+
# using this as a workaround:
|
706
|
+
if rule['src_len'] == 0:
|
707
|
+
del rule['src']
|
708
|
+
if rule['dst_len'] == 0:
|
709
|
+
del rule['dst']
|
710
|
+
|
665
711
|
self.netns.ipr.rule('del', **rule)
|
666
712
|
except Exception as err:
|
667
713
|
if not isinstance(err, netlinkerror_classes):
|