mirror of
https://github.com/CumulusNetworks/ifupdown2.git
synced 2024-05-06 15:54:50 +00:00
Modified ifupdown support for vxlan head end replication
Replaced vxlan-peernodeip attribute with vxlan-remoteip. Updated the vxlan and iproute2 modules to configure head end replication using bridge fdb commands. (cherry picked from commit 567f445fc4a1828fc2aac0da3f2402a185656cb5) Conflicts: packages/ifupdown2/addons/vxlan.py packages/ifupdown2/ifupdownaddons/iproute2.py Conflicts: ifupdown2/addons/vxlan.py ifupdown2/ifupdownaddons/iproute2.py
This commit is contained in:
@@ -20,9 +20,9 @@ class vxlan(moduleBase):
|
||||
'vxlan-svcnodeip' :
|
||||
{'help' : 'vxlan id',
|
||||
'example': ['vxlan-svcnodeip 172.16.22.125']},
|
||||
'vxlan-peernodeip' :
|
||||
{'help' : 'vxlan peer node ip',
|
||||
'example': ['vxlan-peernodeip 172.16.22.127']},
|
||||
'vxlan-remoteip' :
|
||||
{'help' : 'vxlan remote ip',
|
||||
'example': ['vxlan-remoteip 172.16.22.127']},
|
||||
'vxlan-learning' :
|
||||
{'help' : 'vxlan learning on/off',
|
||||
'example': ['vxlan-learning off'],
|
||||
@@ -44,8 +44,9 @@ class vxlan(moduleBase):
|
||||
self.ipcmd.link_create_vxlan(ifaceobj.name, vxlanid,
|
||||
localtunnelip=ifaceobj.get_attr_value_first('vxlan-local-tunnelip'),
|
||||
svcnodeips=ifaceobj.get_attr_value('vxlan-svcnodeip'),
|
||||
peernodeips=ifaceobj.get_attr_value('vxlan-peernodeip'),
|
||||
learning=ifaceobj.get_attr_value_first('vxlan-learning'))
|
||||
remoteips=ifaceobj.get_attr_value('vxlan-remoteip'),
|
||||
learning=ifaceobj.get_attr_value_first('vxlan-learning'),
|
||||
ageing=ifaceobj.get_attr_value_first('vxlan-ageing'))
|
||||
if ifaceobj.addr_method == 'manual':
|
||||
rtnetlink_api.rtnl_api.link_set(ifaceobj.name, "up")
|
||||
|
||||
@@ -96,11 +97,13 @@ class vxlan(moduleBase):
|
||||
ifaceobj.get_attr_value('vxlan-svcnodeip'),
|
||||
vxlanattrs.get('svcnode', []))
|
||||
|
||||
self._query_check_n_update_addresses(ifaceobjcurr, 'vxlan-peernodeip',
|
||||
ifaceobj.get_attr_value('vxlan-peernodeip'),
|
||||
vxlanattrs.get('peernode', []))
|
||||
self._query_check_n_update_addresses(ifaceobjcurr, 'vxlan-remoteip',
|
||||
ifaceobj.get_attr_value('vxlan-remoteip'),
|
||||
vxlanattrs.get('remote', []))
|
||||
|
||||
learning = ifaceobj.get_attr_value_first('vxlan-learning')
|
||||
if not learning:
|
||||
learning = 'on'
|
||||
running_learning = vxlanattrs.get('learning')
|
||||
if learning == running_learning:
|
||||
ifaceobjcurr.update_config_with_status('vxlan-learning',
|
||||
@@ -123,9 +126,9 @@ class vxlan(moduleBase):
|
||||
if attrval:
|
||||
[ifaceobjrunning.update_config('vxlan-svcnode', a)
|
||||
for a in attrval]
|
||||
attrval = vxlanattrs.get('peernode')
|
||||
attrval = vxlanattrs.get('remote')
|
||||
if attrval:
|
||||
[ifaceobjrunning.update_config('vxlan-peernode', a)
|
||||
[ifaceobjrunning.update_config('vxlan-remoteip', a)
|
||||
for a in attrval]
|
||||
attrval = vxlanattrs.get('learning')
|
||||
if attrval and attrval == 'on':
|
||||
|
@@ -9,6 +9,8 @@ from collections import OrderedDict
|
||||
from utilsbase import *
|
||||
from cache import *
|
||||
|
||||
VXLAN_UDP_PORT = 4789
|
||||
|
||||
class iproute2(utilsBase):
|
||||
""" This class contains helper methods to cache and interact with the
|
||||
commands in the iproute2 package """
|
||||
@@ -68,6 +70,8 @@ class iproute2(utilsBase):
|
||||
elif citems[i] == 'vxlan' and citems[i+1] == 'id':
|
||||
vattrs = {'vxlanid' : citems[i+2],
|
||||
'svcnode' : [],
|
||||
'remote' : [],
|
||||
'ageing' : citems[i+2],
|
||||
'learning': 'on'}
|
||||
for j in range(i+2, len(citems)):
|
||||
if citems[j] == 'local':
|
||||
@@ -78,6 +82,10 @@ class iproute2(utilsBase):
|
||||
vattrs['peernode'].append(citems[j+1])
|
||||
elif citems[j] == 'nolearning':
|
||||
vattrs['learning'] = 'off'
|
||||
# get vxlan peer nodes
|
||||
peers = self.get_vxlan_peers(ifname)
|
||||
if peers:
|
||||
vattrs['remote'] = peers
|
||||
linkattrs['linkinfo'] = vattrs
|
||||
break
|
||||
#linkattrs['alias'] = self.read_file_oneline(
|
||||
@@ -456,35 +464,80 @@ class iproute2(utilsBase):
|
||||
self.exec_command('ip %s' %cmd)
|
||||
self._cache_update([name], {})
|
||||
|
||||
def get_vxlan_peers(self, dev):
|
||||
cmd = 'bridge fdb show brport %s' % dev
|
||||
cur_peers = []
|
||||
try:
|
||||
ps = subprocess.Popen((cmd).split(), stdout=subprocess.PIPE, close_fds=True)
|
||||
output = subprocess.check_output(('grep', '00:00:00:00:00:00'), stdin=ps.stdout)
|
||||
ps.wait()
|
||||
try:
|
||||
ppat = re.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+')
|
||||
for l in output.split('\n'):
|
||||
m = ppat.search(l)
|
||||
if m:
|
||||
cur_peers.append(m.group(1))
|
||||
except:
|
||||
self.logger.warn('error parsing ip link output')
|
||||
pass
|
||||
except subprocess.CalledProcessError as e:
|
||||
if e.returncode != 1:
|
||||
self.logger.error(str(e))
|
||||
|
||||
return cur_peers
|
||||
|
||||
def link_create_vxlan(self, name, vxlanid,
|
||||
localtunnelip=None,
|
||||
svcnodeips=None,
|
||||
peernodeips=None,
|
||||
learning='on'):
|
||||
if svcnodeips and peernodeips:
|
||||
raise Exception("svcnodeip and peernodeip is mutually exclusive")
|
||||
remoteips=None,
|
||||
learning='on',
|
||||
ageing=None):
|
||||
if svcnodeips and remoteips:
|
||||
raise Exception("svcnodeip and remoteip is mutually exclusive")
|
||||
args = ''
|
||||
if localtunnelip:
|
||||
args += ' local %s' %localtunnelip
|
||||
if svcnodeips:
|
||||
for s in svcnodeips:
|
||||
args += ' svcnode %s' %s
|
||||
if peernodeips:
|
||||
for s in peernodeips:
|
||||
args += ' peernode %s' %s
|
||||
if ageing:
|
||||
args += ' ageing %s' %ageing
|
||||
if learning == 'off':
|
||||
args += ' nolearning'
|
||||
|
||||
|
||||
if self.link_exists(name):
|
||||
cmd = 'link set dev %s type vxlan ' %(name)
|
||||
cmd = 'link set dev %s type vxlan dstport %d' %(name, VXLAN_UDP_PORT)
|
||||
else:
|
||||
cmd = 'link add dev %s type vxlan id %s' %(name, vxlanid)
|
||||
cmd = 'link add dev %s type vxlan id %s dstport %d' %(name, vxlanid, VXLAN_UDP_PORT)
|
||||
cmd += args
|
||||
|
||||
if self.ipbatch and not self.ipbatch_pause:
|
||||
self.add_to_batch(cmd)
|
||||
else:
|
||||
self.exec_command('ip %s' %cmd)
|
||||
|
||||
# figure out the diff for remotes and do the bridge fdb updates
|
||||
cur_peers = set(self.get_vxlan_peers(name))
|
||||
if remoteips:
|
||||
new_peers = set(remoteips)
|
||||
del_list = cur_peers.difference(new_peers)
|
||||
add_list = new_peers.difference(cur_peers)
|
||||
else:
|
||||
del_list = cur_peers
|
||||
add_list = []
|
||||
|
||||
try:
|
||||
for addr in del_list:
|
||||
self.bridge_fdb_del(name, '00:00:00:00:00:00', None, True, addr)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
for addr in add_list:
|
||||
self.bridge_fdb_append(name, '00:00:00:00:00:00', None, True, addr)
|
||||
except:
|
||||
pass
|
||||
|
||||
# XXX: update linkinfo correctly
|
||||
self._cache_update([name], {})
|
||||
|
||||
@@ -620,23 +673,43 @@ class iproute2(utilsBase):
|
||||
[self.exec_command('bridge vlan del vid %s dev %s %s'
|
||||
%(v, bridgeportname, target)) for v in vids]
|
||||
|
||||
def bridge_fdb_add(self, dev, address, vlan=None, bridge=True):
|
||||
def bridge_fdb_add(self, dev, address, vlan=None, bridge=True, remote=None):
|
||||
target = 'self' if bridge else ''
|
||||
vlan_str = ''
|
||||
if vlan:
|
||||
self.exec_command('bridge fdb replace %s dev %s vlan %s %s'
|
||||
%(address, dev, vlan, target))
|
||||
else:
|
||||
self.exec_command('bridge fdb replace %s dev %s %s'
|
||||
%(address, dev, target))
|
||||
vlan_str = 'vlan %s ' % vlan
|
||||
|
||||
def bridge_fdb_del(self, dev, address, vlan=None, bridge=True):
|
||||
dst_str = ''
|
||||
if remote:
|
||||
dst_str = 'dst %s ' % remote
|
||||
|
||||
self.exec_command('bridge fdb replace %s dev %s %s %s %s'
|
||||
%(address, dev, vlan_str, target, dst_str))
|
||||
|
||||
def bridge_fdb_append(self, dev, address, vlan=None, bridge=True, remote=None):
|
||||
target = 'self' if bridge else ''
|
||||
vlan_str = ''
|
||||
if vlan:
|
||||
self.exec_command('bridge fdb del %s dev %s vlan %s %s'
|
||||
%(address, dev, vlan, target))
|
||||
else:
|
||||
self.exec_command('bridge fdb del %s dev %s %s'
|
||||
%(address, dev, target))
|
||||
vlan_str = 'vlan %s ' % vlan
|
||||
|
||||
dst_str = ''
|
||||
if remote:
|
||||
dst_str = 'dst %s ' % remote
|
||||
|
||||
self.exec_command('bridge fdb append %s dev %s %s %s %s'
|
||||
%(address, dev, vlan_str, target, dst_str))
|
||||
|
||||
def bridge_fdb_del(self, dev, address, vlan=None, bridge=True, remote=None):
|
||||
target = 'self' if bridge else ''
|
||||
vlan_str = ''
|
||||
if vlan:
|
||||
vlan_str = 'vlan %s ' % vlan
|
||||
|
||||
dst_str = ''
|
||||
if remote:
|
||||
dst_str = 'dst %s ' % remote
|
||||
self.exec_command('bridge fdb del %s dev %s %s %s %s'
|
||||
%(address, dev, vlan_str, target, dst_str))
|
||||
|
||||
def bridge_is_vlan_aware(self, bridgename):
|
||||
filename = '/sys/class/net/%s/bridge/vlan_filtering' %bridgename
|
||||
|
Reference in New Issue
Block a user