Skip to content

Commit 3e52604

Browse files
authored
Add ip_prefix len based on proxy_arp status (#1046)
* Add ip_prefix len based on proxy_arp status and relevant test
1 parent b4a53be commit 3e52604

File tree

5 files changed

+176
-56
lines changed

5 files changed

+176
-56
lines changed

scripts/neighbor_advertiser

+50-50
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,13 @@ import argparse
1111
import json
1212
import os
1313
import requests
14-
import subprocess
1514
import sys
1615
import time
1716
import traceback
1817
import warnings
1918

2019
from sonic_py_common import logger
21-
from swsssdk import ConfigDBConnector
20+
from swsssdk import ConfigDBConnector, SonicV2Connector
2221
from netaddr import IPAddress, IPNetwork
2322

2423

@@ -76,6 +75,15 @@ def connect_config_db():
7675
config_db = ConfigDBConnector()
7776
config_db.connect()
7877

78+
#
79+
# Global variable of app_db
80+
#
81+
appl_db = None
82+
83+
def connect_app_db():
84+
global appl_db
85+
appl_db = SonicV2Connector(host="127.0.0.1")
86+
appl_db.connect(appl_db.APPL_DB)
7987

8088
#
8189
# Check if a DIP returned from ferret is in any of this switch's VLANs
@@ -125,13 +133,9 @@ def get_switch_hwsku():
125133

126134

127135
def extract_ip_ver_addr(ip_prefix):
128-
addr = ip_prefix.split('/')[0]
129-
130-
if ':' in addr:
131-
ver = 6
132-
else:
133-
ver = 4
134-
136+
ip = IPNetwork(ip_prefix)
137+
addr = str(ip.ip)
138+
ver = ip.ip.version
135139
return (ver, addr)
136140

137141

@@ -201,65 +205,40 @@ def get_vlan_interface_vxlan_id(vlan_intf_name):
201205
return vlan_intf_name[4:]
202206

203207

204-
def get_vlan_addr(vlan_intf_name, ip_ver):
208+
def get_vlan_addr_prefix(vlan_intf_name, ip_ver):
205209
vlan_intfs = config_db.get_table('VLAN_INTERFACE')
206210
vlan_addr = []
211+
vlan_prefix = []
207212

208213
for intf in vlan_intfs.keys():
209214
if not is_ip_prefix_in_key(intf):
210215
continue
211216
if vlan_intf_name in intf:
212-
intf_ip_prefix = intf[1]
213-
(intf_ip_ver, intf_ip_addr) = extract_ip_ver_addr(intf_ip_prefix)
217+
intf_ip = IPNetwork(intf[1])
218+
intf_ip_addr = str(intf_ip.ip)
219+
intf_ip_ver = intf_ip.ip.version
220+
intf_prefixlen = intf_ip.prefixlen
214221
if intf_ip_ver == ip_ver:
215222
vlan_addr.append(intf_ip_addr)
223+
vlan_prefix.append(intf_prefixlen)
216224

217-
return vlan_addr
225+
return vlan_addr, vlan_prefix
218226

219227

220228
def get_vlan_addresses(vlan_interface):
221229
vlan_id = get_vlan_interface_vlan_id(vlan_interface)
222230
vxlan_id = get_vlan_interface_vxlan_id(vlan_interface)
223231

224232
mac_addr = None
225-
ipv4_addr = []
226-
ipv6_addr = []
227-
228-
'''
229-
Sample output for "ip addr show Vlan101"
230-
231-
218: Vlan101@Bridge: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
232-
link/ether 98:5d:82:01:d8:48 brd ff:ff:ff:ff:ff:ff
233-
inet 10.171.22.113/29 scope global Vlan101
234-
valid_lft forever preferred_lft forever
235-
inet6 2603:10b0:10f:843c::1/64 scope global
236-
valid_lft forever preferred_lft forever
237-
inet6 fe80::9a5d:82ff:fe01:d848/64 scope link
238-
valid_lft forever preferred_lft forever
239-
'''
240-
try:
241-
out = subprocess.check_output(['ip', 'addr', 'show', vlan_interface])
242-
for line in out.splitlines():
243-
keys=line.strip().split(' ')
244-
if keys[0] == 'inet':
245-
ipv4_addr.append(keys[1].split('/')[0])
246-
elif keys[0] == 'inet6':
247-
ipv6_addr.append(keys[1].split('/')[0])
248-
elif keys[0] == 'link/ether':
249-
mac_addr = keys[1]
250-
except Exception:
251-
log.log_error('failed to get %s addresses from o.s.' % vlan_interface)
233+
ipv4_addr, ipv4_prefix = get_vlan_addr_prefix(vlan_interface, 4)
234+
ipv6_addr, ipv6_prefix = get_vlan_addr_prefix(vlan_interface, 6)
252235

236+
metadata = config_db.get_table('DEVICE_METADATA')
237+
mac_addr = metadata['localhost']['mac']
253238
if not mac_addr:
254239
mac_addr = get_vlan_interface_mac_address(vlan_interface)
255240

256-
if not ipv4_addr:
257-
ipv4_addr = get_vlan_addr(vlan_interface, 4)
258-
259-
if not ipv6_addr:
260-
ipv6_addr = get_vlan_addr(vlan_interface, 6)
261-
262-
return vlan_id, vxlan_id, ipv4_addr, ipv6_addr, mac_addr
241+
return vlan_id, vxlan_id, ipv4_addr, ipv4_prefix, ipv6_addr, ipv6_prefix, mac_addr
263242

264243
#
265244
# Set up neighbor advertiser slice on Ferret
@@ -281,28 +260,46 @@ def construct_neighbor_advertiser_slice():
281260

282261
all_vlan_interfaces = get_vlan_interfaces()
283262

263+
vlan_intf_table = config_db.get_table('VLAN_INTERFACE')
264+
265+
vxlanPort = appl_db.get(appl_db.APPL_DB, 'SWITCH_TABLE:switch', 'vxlan_port')
266+
284267
for vlan_interface in all_vlan_interfaces:
285-
vlan_id, vxlan_id, ipv4_addr, ipv6_addr, mac_addr = get_vlan_addresses(vlan_interface)
268+
vlan_id, vxlan_id, ipv4_addr, ipv4_prefix, ipv6_addr, ipv6_prefix, mac_addr = get_vlan_addresses(vlan_interface)
286269

287270
if not mac_addr:
288271
log.log_warning('Cannot find mac addr of vlan interface {}'.format(vlan_interface))
289272
continue
290273

291274
ipv4_mappings = []
275+
ipv6_mappings = []
276+
ctr = 0
292277
for addr in ipv4_addr:
278+
if 'proxy_arp' in vlan_intf_table[vlan_interface] and vlan_intf_table[vlan_interface]['proxy_arp'] == 'enabled':
279+
ipPrefixLen = str(ipv4_prefix[ctr])
280+
else:
281+
ipPrefixLen = '32'
293282
mapping = {
294283
'ipAddr': addr,
284+
'ipPrefixLen': ipPrefixLen,
295285
'macAddr': mac_addr
296286
}
297287
ipv4_mappings.append(mapping)
288+
ctr += 1
298289

299-
ipv6_mappings = []
290+
ctr = 0
300291
for addr in ipv6_addr:
292+
if 'proxy_arp' in vlan_intf_table[vlan_interface] and vlan_intf_table[vlan_interface]['proxy_arp'] == 'enabled':
293+
ipPrefixLen = str(ipv6_prefix[ctr])
294+
else:
295+
ipPrefixLen = '128'
301296
mapping = {
302297
'ipAddr': addr,
298+
'ipPrefixLen': ipPrefixLen,
303299
'macAddr': mac_addr
304300
}
305301
ipv6_mappings.append(mapping)
302+
ctr += 1
306303

307304
vlan_interface_obj = {
308305
'vlanId': vlan_id,
@@ -311,6 +308,9 @@ def construct_neighbor_advertiser_slice():
311308
'ipv6AddrMappings': ipv6_mappings
312309
}
313310

311+
if vxlanPort:
312+
vlan_interface_obj['vxlanPort'] = vxlanPort
313+
314314
vlan_interfaces_obj.append(vlan_interface_obj)
315315

316316
slice_obj = {
@@ -539,7 +539,7 @@ def main():
539539
sys.exit(1)
540540

541541
connect_config_db()
542-
542+
connect_app_db()
543543
if operation_mode == 'set':
544544
set_success = False
545545

tests/mock_tables/appl_db.json

+3
Original file line numberDiff line numberDiff line change
@@ -157,5 +157,8 @@
157157
"admin_status": "up",
158158
"mtu": "9100",
159159
"oper_status": "up"
160+
},
161+
"SWITCH_TABLE:switch": {
162+
"vxlan_port": "13550"
160163
}
161164
}

tests/mock_tables/config_db.json

+30
Original file line numberDiff line numberDiff line change
@@ -424,9 +424,16 @@
424424
"dhcp_servers@": "192.0.0.1,192.0.0.2,192.0.0.3,192.0.0.4",
425425
"vlanid": "1000"
426426
},
427+
"VLAN|Vlan2000": {
428+
"dhcp_servers@": "192.0.0.1,192.0.0.2,192.0.0.3,192.0.0.4",
429+
"vlanid": "2000"
430+
},
427431
"VLAN_INTERFACE|Vlan1000": {
428432
"NULL": "NULL"
429433
},
434+
"VLAN_INTERFACE|Vlan2000": {
435+
"proxy_arp": "enabled"
436+
},
430437
"VLAN_INTERFACE|Vlan1000|192.168.0.1/21": {
431438
"NULL": "NULL"
432439
},
@@ -445,6 +452,18 @@
445452
"VLAN_MEMBER|Vlan1000|Ethernet16": {
446453
"tagging_mode": "untagged"
447454
},
455+
"VLAN_INTERFACE|Vlan2000|192.168.0.10/21": {
456+
"NULL": "NULL"
457+
},
458+
"VLAN_INTERFACE|Vlan2000|fc02:1011::1/64": {
459+
"NULL": "NULL"
460+
},
461+
"VLAN_MEMBER|Vlan2000|Ethernet24": {
462+
"tagging_mode": "untagged"
463+
},
464+
"VLAN_MEMBER|Vlan2000|Ethernet28": {
465+
"tagging_mode": "untagged"
466+
},
448467
"PORTCHANNEL|PortChannel1001": {
449468
"admin_status": "up",
450469
"members@": "Ethernet32",
@@ -579,6 +598,17 @@
579598
"auto_restart": "enabled",
580599
"high_mem_alert": "disabled"
581600
},
601+
"DEVICE_METADATA|localhost": {
602+
"default_bgp_status": "down",
603+
"default_pfcwd_status": "enable",
604+
"deployment_id": "1",
605+
"docker_routing_config_mode": "separated",
606+
"hostname": "sonic-switch",
607+
"hwsku": "Mellanox-SN3800-D112C8",
608+
"mac": "1d:34:db:16:a6:00",
609+
"platform": "x86_64-mlnx_msn3800-r0",
610+
"type": "ToRRouter"
611+
},
582612
"DEVICE_NEIGHBOR|Ethernet4": {
583613
"name": "Servers0",
584614
"port": "eth0"

tests/neighbor_advertiser_test.py

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import sys
2+
import os
3+
import pytest
4+
from swsssdk import ConfigDBConnector
5+
6+
test_path = os.path.dirname(os.path.abspath(__file__))
7+
modules_path = os.path.dirname(test_path)
8+
scripts_path = os.path.join(modules_path, "scripts")
9+
sys.path.insert(0, modules_path)
10+
11+
from imp import load_source
12+
load_source('neighbor_advertiser', scripts_path+'/neighbor_advertiser')
13+
import neighbor_advertiser
14+
15+
class TestNeighborAdvertiser(object):
16+
@pytest.fixture
17+
def set_up(self):
18+
neighbor_advertiser.connect_config_db()
19+
neighbor_advertiser.connect_app_db()
20+
21+
def test_neighbor_advertiser_slice(self, set_up):
22+
output = neighbor_advertiser.construct_neighbor_advertiser_slice()
23+
expected_output = dict({
24+
'respondingSchemes': {'durationInSec': 300},
25+
'switchInfo': {'ipv6Addr': '', 'hwSku': 'Mellanox-SN3800-D112C8', 'ipv4Addr': '', 'name': 'sonic-switch'},
26+
'vlanInterfaces': [{
27+
'ipv4AddrMappings': [
28+
{'macAddr': '1d:34:db:16:a6:00', 'ipAddr': '192.168.0.1', 'ipPrefixLen': '32'}
29+
],
30+
'ipv6AddrMappings': [
31+
{'macAddr': '1d:34:db:16:a6:00', 'ipAddr': 'fc02:1000::1', 'ipPrefixLen': '128'}
32+
],
33+
'vxlanId': u'1000',
34+
'vlanId': u'1000',
35+
'vxlanPort': '13550'
36+
},
37+
{
38+
'ipv4AddrMappings': [
39+
{'macAddr': '1d:34:db:16:a6:00', 'ipAddr': '192.168.0.10', 'ipPrefixLen': '21'}
40+
],
41+
'ipv6AddrMappings': [
42+
{'macAddr': '1d:34:db:16:a6:00', 'ipAddr': 'fc02:1011::1', 'ipPrefixLen': '64'}
43+
],
44+
'vxlanId': u'2000',
45+
'vlanId': u'2000',
46+
'vxlanPort': '13550'
47+
}]
48+
})
49+
assert output == expected_output

0 commit comments

Comments
 (0)