/
lagg.py
84 lines (63 loc) · 2.67 KB
/
lagg.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import enum
import logging
import pathlib
from pyroute2 import NDB
import middlewared.plugins.interface.netif_linux.interface as interface
from .utils import run
logger = logging.getLogger(__name__)
__all__ = ["AggregationProtocol", "create_lagg"]
class AggregationProtocol(enum.Enum):
LACP = "802.3ad"
FAILOVER = "active-backup"
LOADBALANCE = "balance-xor"
def create_lagg(name):
with NDB(log="off") as ndb:
ndb.interfaces.create(ifname=name, kind="bond").set("state", "up").commit()
class LaggMixin:
@property
def protocol(self):
value = self._sysfs_read(f"/sys/devices/virtual/net/{self.name}/bonding/mode").split()[0]
for protocol in AggregationProtocol:
if protocol.value == value:
return protocol
@protocol.setter
def protocol(self, value):
for port in self.ports:
self.delete_port(port[0])
run(["ip", "link", "set", self.name, "type", "bond", "mode", value.value])
@property
def xmit_hash_policy(self):
if self.protocol in (AggregationProtocol.LACP, AggregationProtocol.LOADBALANCE):
# this option only applies to 802.3ad and/or balance-xor
return self._sysfs_read(self.get_options_path("xmit_hash_policy")).split()[0]
@xmit_hash_policy.setter
def xmit_hash_policy(self, value):
run(["ip", "link", "set", self.name, "type", "bond", "xmit_hash_policy", value])
@property
def lacpdu_rate(self):
if self.protocol == AggregationProtocol.LACP:
# this option only applies to 802.3ad
return self._sysfs_read(self.get_options_path("lacp_rate")).split()[0]
@lacpdu_rate.setter
def lacpdu_rate(self, value):
run(["ip", "link", "set", self.name, "type", "bond", "lacp_rate", value])
@property
def primary_interface(self):
if self.protocol == AggregationProtocol.FAILOVER:
return self._sysfs_read(self.get_options_path("primary")).strip() or None
@primary_interface.setter
def primary_interface(self, value):
run(["ip", "link", "set", self.name, "type", "bond", "primary", value])
@property
def ports(self):
ports = []
for port in self._sysfs_read(f"/sys/devices/virtual/net/{self.name}/bonding/slaves").split():
ports.append((port, set()))
return ports
def get_options_path(self, value):
return str(pathlib.Path(f"/sys/class/net/{self.name}/bonding/").joinpath(value))
def add_port(self, name):
interface.Interface(name).down()
run(["ip", "link", "set", name, "master", self.name])
def delete_port(self, name):
run(["ip", "link", "set", name, "nomaster"])