]>
Commit | Line | Data |
---|---|---|
e0a84778 VB |
1 | import pytest |
2 | import pyroute2 | |
3 | import struct | |
36d0c286 | 4 | import time |
e0a84778 VB |
5 | from .namespaces import Namespace |
6 | ||
7 | ||
8 | def int_to_mac(c): | |
9 | """Turn an int into a MAC address.""" | |
10 | return ":".join(('{:02x}',)*6).format( | |
11 | *struct.unpack('BBBBBB', c.to_bytes(6, byteorder='big'))) | |
12 | ||
13 | ||
14 | class LinksFactory(object): | |
15 | """A factory for veth pair of interfaces and other L2 stuff. | |
16 | ||
17 | Each veth interfaces will get named ethX with X strictly | |
18 | increasing at each call. | |
19 | ||
20 | """ | |
21 | ||
22 | def __init__(self): | |
23 | # We create all those links in a dedicated namespace to avoid | |
24 | # conflict with other namespaces. | |
25 | self.ns = Namespace('net') | |
26 | self.count = 0 | |
27 | ||
28 | def __call__(self, *args): | |
29 | return self.veth(*args) | |
30 | ||
36d0c286 | 31 | def veth(self, ns1, ns2, sleep=0): |
e0a84778 VB |
32 | """Create a veth pair between two namespaces.""" |
33 | with self.ns: | |
34 | # First, create a link | |
35 | first = 'eth{}'.format(self.count) | |
36 | second = 'eth{}'.format(self.count + 1) | |
37 | ipr = pyroute2.IPRoute() | |
38 | ipr.link_create(ifname=first, | |
39 | peer=second, | |
40 | kind='veth') | |
41 | idx = [ipr.link_lookup(ifname=x)[0] | |
42 | for x in (first, second)] | |
43 | ||
44 | # Set an easy to remember MAC address | |
45 | ipr.link('set', index=idx[0], | |
46 | address=int_to_mac(self.count + 1)) | |
47 | ipr.link('set', index=idx[1], | |
48 | address=int_to_mac(self.count + 2)) | |
49 | ||
50 | # Then, move each to the target namespace | |
51 | ipr.link('set', index=idx[0], net_ns_fd=ns1.fd('net')) | |
52 | ipr.link('set', index=idx[1], net_ns_fd=ns2.fd('net')) | |
53 | ||
54 | # And put them up | |
55 | with ns1: | |
56 | ipr = pyroute2.IPRoute() | |
57 | ipr.link('set', index=idx[0], state='up') | |
36d0c286 | 58 | time.sleep(sleep) |
e0a84778 VB |
59 | with ns2: |
60 | ipr = pyroute2.IPRoute() | |
61 | ipr.link('set', index=idx[1], state='up') | |
62 | ||
63 | self.count += 2 | |
64 | ||
65 | def bridge(self, name, *ifaces): | |
66 | """Create a bridge.""" | |
67 | ipr = pyroute2.IPRoute() | |
68 | # Create the bridge | |
69 | ipr.link_create(ifname=name, | |
70 | kind='bridge') | |
71 | idx = ipr.link_lookup(ifname=name)[0] | |
72 | # Attach interfaces | |
73 | for iface in ifaces: | |
74 | port = ipr.link_lookup(ifname=iface)[0] | |
75 | ipr.link('set', index=port, master=idx) | |
76 | # Put the bridge up | |
77 | ipr.link('set', index=idx, state='up') | |
78 | return idx | |
79 | ||
5f658dac VB |
80 | def _bond_or_team(self, kind, name, *ifaces): |
81 | """Create a bond or a team.""" | |
a3bea2f6 | 82 | ipr = pyroute2.RawIPRoute() |
e0a84778 VB |
83 | # Create the bond |
84 | ipr.link_create(ifname=name, | |
5f658dac | 85 | kind=kind) |
e0a84778 VB |
86 | idx = ipr.link_lookup(ifname=name)[0] |
87 | # Attach interfaces | |
88 | for iface in ifaces: | |
89 | slave = ipr.link_lookup(ifname=iface)[0] | |
90 | ipr.link('set', index=slave, state='down') | |
91 | ipr.link('set', index=slave, master=idx) | |
92 | # Put the bond up | |
93 | ipr.link('set', index=idx, state='up') | |
94 | return idx | |
95 | ||
5f658dac VB |
96 | def team(self, name, *ifaces): |
97 | """Create a team.""" | |
98 | # Unfortunately, pyroute2 will try to run teamd too. This | |
99 | # doesn't work. | |
100 | return self._bond_or_team("team", name, *ifaces) | |
101 | ||
102 | def bond(self, name, *ifaces): | |
103 | """Create a bond.""" | |
104 | return self._bond_or_team("bond", name, *ifaces) | |
105 | ||
e0a84778 VB |
106 | def vlan(self, name, id, iface): |
107 | """Create a VLAN.""" | |
108 | ipr = pyroute2.IPRoute() | |
109 | idx = ipr.link_lookup(ifname=iface)[0] | |
110 | ipr.link_create(ifname=name, | |
111 | kind='vlan', | |
112 | vlan_id=id, | |
113 | link=idx) | |
114 | idx = ipr.link_lookup(ifname=name)[0] | |
115 | ipr.link('set', index=idx, state='up') | |
116 | return idx | |
117 | ||
118 | def up(self, name): | |
119 | ipr = pyroute2.IPRoute() | |
120 | idx = ipr.link_lookup(ifname=name)[0] | |
121 | ipr.link('set', index=idx, state='up') | |
122 | ||
123 | def down(self, name): | |
124 | ipr = pyroute2.IPRoute() | |
125 | idx = ipr.link_lookup(ifname=name)[0] | |
126 | ipr.link('set', index=idx, state='down') | |
127 | ||
128 | def remove(self, name): | |
129 | ipr = pyroute2.IPRoute() | |
130 | idx = ipr.link_lookup(ifname=name)[0] | |
131 | ipr.link_remove(idx) | |
132 | ||
133 | ||
134 | @pytest.fixture | |
135 | def links(): | |
136 | return LinksFactory() |