]>
git.proxmox.com Git - mirror_ifupdown2.git/blob - ifupdown2/addons/addressvirtual.py
98ac536fb09decff035a0b094d0618ba7c64ec7d
3 # Copyright 2014 Cumulus Networks, Inc. All rights reserved.
4 # Author: Roopa Prabhu, roopa@cumulusnetworks.com
7 from ifupdown
.iface
import *
8 from ifupdownaddons
.modulebase
import moduleBase
9 from ifupdownaddons
.iproute2
import iproute2
10 import ifupdown
.rtnetlink_api
as rtnetlink_api
11 from ipaddr
import IPNetwork
16 class addressvirtual(moduleBase
):
17 """ ifupdown2 addon module to configure virtual addresses """
19 _modinfo
= {'mhelp' : 'address module configures virtual addresses for ' +
20 'interfaces. It creates a macvlan interface for ' +
21 'every mac ip address-virtual line',
24 { 'help' : 'bridge router virtual mac and ip',
25 'example' : ['address-virtual 00:11:22:33:44:01 11.0.1.254/24 11.0.1.254/24']}
29 def __init__(self
, *args
, **kargs
):
30 moduleBase
.__init
__(self
, *args
, **kargs
)
32 self
._bridge
_fdb
_query
_cache
= {}
34 def _is_supported(self
, ifaceobj
):
35 if ifaceobj
.get_attr_value_first('address-virtual'):
39 def _get_macvlan_prefix(self
, ifaceobj
):
40 return '%s-v' %ifaceobj
.name
[0:13].replace('.', '-')
42 def _add_addresses_to_bridge(self
, ifaceobj
, hwaddress
):
43 # XXX: batch the addresses
44 if '.' in ifaceobj
.name
:
45 (bridgename
, vlan
) = ifaceobj
.name
.split('.')
46 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
47 [self
.ipcmd
.bridge_fdb_add(bridgename
, addr
,
48 vlan
) for addr
in hwaddress
]
49 elif self
.ipcmd
.is_bridge(ifaceobj
.name
):
50 [self
.ipcmd
.bridge_fdb_add(ifaceobj
.name
, addr
)
51 for addr
in hwaddress
]
53 def _remove_addresses_from_bridge(self
, ifaceobj
, hwaddress
):
54 # XXX: batch the addresses
56 if '.' in ifaceobj
.name
:
57 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
58 (bridgename
, vlan
) = ifaceobj
.name
.split('.')
59 elif self
.ipcmd
.is_bridge(ifaceobj
.name
):
61 bridgename
= ifaceobj
.name
64 for addr
in hwaddress
:
66 self
.ipcmd
.bridge_fdb_del(bridgename
, addr
, vlan
)
68 self
.logger
.debug("%s: %s" %(ifaceobj
.name
, str(e
)))
71 def _get_bridge_fdbs(self
, bridgename
, vlan
):
72 fdbs
= self
._bridge
_fdb
_query
_cache
.get(bridgename
)
74 fdbs
= self
.ipcmd
.bridge_fdb_show_dev(bridgename
)
77 self
._bridge
_fdb
_query
_cache
[bridgename
] = fdbs
80 def _check_addresses_in_bridge(self
, ifaceobj
, hwaddress
):
81 """ If the device is a bridge, make sure the addresses
83 if '.' in ifaceobj
.name
:
84 (bridgename
, vlan
) = ifaceobj
.name
.split('.')
85 if self
.ipcmd
.bridge_is_vlan_aware(bridgename
):
86 fdb_addrs
= self
._get
_bridge
_fdbs
(bridgename
, vlan
)
87 if not fdb_addrs
or hwaddress
not in fdb_addrs
:
91 def _fix_connected_route(self
, ifaceobj
, vifacename
, addr
):
93 # XXX: Hack to make sure the primary address
94 # is the first in the routing table.
96 # We use `ip route get` on the vrr network to see which
97 # device the kernel returns. if it is the mac vlan device,
98 # flap the macvlan device to adjust the routing table entry.
100 # flapping the macvlan device makes sure the macvlan
101 # connected route goes through delete + add, hence adjusting
102 # the order in the routing table.
105 self
.logger
.info('%s: checking route entry ...' %ifaceobj
.name
)
107 route_prefix
= '%s/%d' %(ip
.network
, ip
.prefixlen
)
109 dev
= self
.ipcmd
.ip_route_get_dev(route_prefix
)
110 if dev
and dev
== vifacename
:
111 self
.logger
.info('%s: preferred routing entry ' %ifaceobj
.name
+
112 'seems to be of the macvlan dev %s'
114 ' .. flapping macvlan dev to fix entry.')
115 self
.ipcmd
.link_down(vifacename
)
116 self
.ipcmd
.link_up(vifacename
)
118 self
.logger
.debug('%s: fixing route entry failed (%s)'
122 def _apply_address_config(self
, ifaceobj
, address_virtual_list
):
123 purge_existing
= False if self
.PERFMODE
else True
126 self
.ipcmd
.batch_start()
128 macvlan_prefix
= self
._get
_macvlan
_prefix
(ifaceobj
)
129 for av
in address_virtual_list
:
130 av_attrs
= av
.split()
131 if len(av_attrs
) < 2:
132 self
.logger
.warn("%s: incorrect address-virtual attrs '%s'"
133 %(ifaceobj
.name
, av
))
137 # Create a macvlan device on this device and set the virtual
138 # router mac and ip on it
140 macvlan_ifacename
= '%s%d' %(macvlan_prefix
, av_idx
)
141 if not self
.ipcmd
.link_exists(macvlan_ifacename
):
142 rtnetlink_api
.rtnl_api
.create_macvlan(macvlan_ifacename
,
145 if av_attrs
[0] != 'None':
146 self
.ipcmd
.link_set_hwaddress(macvlan_ifacename
, av_attrs
[0])
147 hwaddress
.append(av_attrs
[0])
148 self
.ipcmd
.addr_add_multiple(macvlan_ifacename
, av_attrs
[1:],
150 # If link existed before, flap the link
152 self
._fix
_connected
_route
(ifaceobj
, macvlan_ifacename
,
155 self
.ipcmd
.batch_commit()
157 # if ifaceobj is a bridge and bridge is a vlan aware bridge
158 # add the vid to the bridge
159 self
._add
_addresses
_to
_bridge
(ifaceobj
, hwaddress
)
161 def _remove_running_address_config(self
, ifaceobj
):
162 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
165 self
.ipcmd
.batch_start()
166 macvlan_prefix
= self
._get
_macvlan
_prefix
(ifaceobj
)
167 for macvlan_ifacename
in glob
.glob("/sys/class/net/%s-*" %macvlan_prefix
):
168 macvlan_ifacename
= os
.path
.basename(macvlan_ifacename
)
169 if not self
.ipcmd
.link_exists(macvlan_ifacename
):
171 hwaddress
.append(self
.ipcmd
.link_get_hwaddress(macvlan_ifacename
))
172 self
.ipcmd
.link_delete(os
.path
.basename(macvlan_ifacename
))
173 # XXX: Also delete any fdb addresses. This requires, checking mac address
174 # on individual macvlan interfaces and deleting the vlan from that.
175 self
.ipcmd
.batch_commit()
177 self
._remove
_addresses
_from
_bridge
(ifaceobj
, hwaddress
)
179 def _remove_address_config(self
, ifaceobj
, address_virtual_list
=None):
180 if not address_virtual_list
:
181 self
._remove
_running
_address
_config
(ifaceobj
)
184 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
187 self
.ipcmd
.batch_start()
189 macvlan_prefix
= self
._get
_macvlan
_prefix
(ifaceobj
)
190 for av
in address_virtual_list
:
191 av_attrs
= av
.split()
192 if len(av_attrs
) < 2:
193 self
.logger
.warn("%s: incorrect address-virtual attrs '%s'"
194 %(ifaceobj
.name
, av
))
198 # Delete the macvlan device on this device
199 macvlan_ifacename
= '%s%d' %(macvlan_prefix
, av_idx
)
200 self
.ipcmd
.link_delete(os
.path
.basename(macvlan_ifacename
))
201 if av_attrs
[0] != 'None':
202 hwaddress
.append(av_attrs
[0])
204 self
.ipcmd
.batch_commit()
205 self
._remove
_addresses
_from
_bridge
(ifaceobj
, hwaddress
)
207 def _up(self
, ifaceobj
):
208 address_virtual_list
= ifaceobj
.get_attr_value('address-virtual')
209 if not address_virtual_list
:
210 # XXX: address virtual is not present. In which case,
211 # delete stale macvlan devices.
212 self
._remove
_address
_config
(ifaceobj
, address_virtual_list
)
215 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
217 self
._apply
_address
_config
(ifaceobj
, address_virtual_list
)
219 def _down(self
, ifaceobj
):
221 self
._remove
_address
_config
(ifaceobj
,
222 ifaceobj
.get_attr_value('address-virtual'))
224 self
.log_warn(str(e
))
226 def _query_check(self
, ifaceobj
, ifaceobjcurr
):
227 address_virtual_list
= ifaceobj
.get_attr_value('address-virtual')
228 if not address_virtual_list
:
230 if not self
.ipcmd
.link_exists(ifaceobj
.name
):
233 macvlan_prefix
= self
._get
_macvlan
_prefix
(ifaceobj
)
234 for address_virtual
in address_virtual_list
:
235 av_attrs
= address_virtual
.split()
236 if len(av_attrs
) < 2:
237 self
.logger
.warn("%s: incorrect address-virtual attrs '%s'"
238 %(ifaceobj
.name
, address_virtual
))
242 # Check if the macvlan device on this interface
243 macvlan_ifacename
= '%s%d' %(macvlan_prefix
, av_idx
)
244 if not self
.ipcmd
.link_exists(macvlan_ifacename
):
245 ifaceobjcurr
.update_config_with_status('address-virtual',
249 # Check mac and ip address
250 rhwaddress
= self
.ipcmd
.link_get_hwaddress(macvlan_ifacename
)
251 raddrs
= self
.ipcmd
.addr_get(macvlan_ifacename
)
252 if not raddrs
or not rhwaddress
:
253 ifaceobjcurr
.update_config_with_status('address-virtual', '', 1)
256 raddrs
= raddrs
.keys()
257 if (rhwaddress
== av_attrs
[0] and raddrs
== av_attrs
[1:] and
258 self
._check
_addresses
_in
_bridge
(ifaceobj
, av_attrs
[0])):
259 ifaceobjcurr
.update_config_with_status('address-virtual',
262 raddress_virtual
= '%s %s' %(rhwaddress
, ' '.join(raddrs
))
263 ifaceobjcurr
.update_config_with_status('address-virtual',
268 def _query_running(self
, ifaceobjrunning
):
269 macvlan_prefix
= self
._get
_macvlan
_prefix
(ifaceobjrunning
)
270 address_virtuals
= glob
.glob("/sys/class/net/%s*" %macvlan_prefix
)
271 for av
in address_virtuals
:
272 macvlan_ifacename
= os
.path
.basename(av
)
273 rhwaddress
= self
.ipcmd
.link_get_hwaddress(macvlan_ifacename
)
274 raddress
= self
.ipcmd
.addr_get(macvlan_ifacename
)
276 self
.logger
.warn('%s: no running addresses'
277 %ifaceobjrunning
.name
)
279 ifaceobjrunning
.update_config('address-virtual',
280 '%s %s' %(rhwaddress
, ''.join(raddress
)))
283 _run_ops
= {'up' : _up
,
285 'query-checkcurr' : _query_check
,
286 'query-running' : _query_running
}
289 """ returns list of ops supported by this module """
290 return self
._run
_ops
.keys()
292 def _init_command_handlers(self
):
294 self
.ipcmd
= iproute2(**self
.get_flags())
296 def run(self
, ifaceobj
, operation
, query_ifaceobj
=None, **extra_args
):
297 """ run vlan configuration on the interface object passed as argument
300 **ifaceobj** (object): iface object
302 **operation** (str): any of 'pre-up', 'post-down', 'query-checkcurr',
305 **query_ifaceobj** (object): query check ifaceobject. This is only
306 valid when op is 'query-checkcurr'. It is an object same as
307 ifaceobj, but contains running attribute values and its config
308 status. The modules can use it to return queried running state
309 of interfaces. status is success if the running state is same
310 as user required state in ifaceobj. error otherwise.
312 if ifaceobj
.type == ifaceType
.BRIDGE_VLAN
:
314 op_handler
= self
._run
_ops
.get(operation
)
317 self
._init
_command
_handlers
()
318 if operation
== 'query-checkcurr':
319 op_handler(self
, ifaceobj
, query_ifaceobj
)
321 op_handler(self
, ifaceobj
)