Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 175 additions & 0 deletions tests/dash/configs/privatelink_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import base64
import socket
import uuid
from ipaddress import ip_address as IP

from dash_api.appliance_pb2 import Appliance
from dash_api.vnet_pb2 import Vnet
from dash_api.eni_pb2 import Eni, State
from dash_api.eni_route_pb2 import EniRoute
from dash_api.route_pb2 import Route
from dash_api.vnet_mapping_pb2 import VnetMapping
from dash_api.route_type_pb2 import RouteType, RoutingType, ActionType, EncapType
from dash_api.route_group_pb2 import RouteGroup
from google.protobuf.json_format import ParseDict

VNET_ENCAP = "vnet_encap"
VNET_DIRECT = "vnet_direct"
PRIVATELINK = "privatelink"
DECAP = "decap"

SIP = "10.2.0.1"
INBOUND_UNDERLAY_IP = "25.1.1.1"
OUTBOUND_UNDERLAY_IP = "101.1.2.3"
VNET_MAP_IP1 = "10.1.1.5"
VNET_MAP_IP2 = "10.1.2.5"
Comment thread
theasianpianist marked this conversation as resolved.
Outdated
OUTBOUND_ROUTE_PREFIX1 = "10.1.1.0/24"
OUTBOUND_ROUTE_PREFIX2 = "10.1.2.0/24"
OVERLAY_IP = "10.0.0.6"
PL_ENCODING_IP = "::56b2:0:ff71:0:0"
PL_ENCODING_MASK = "::ffff:ffff:ffff:0:0"
PL_UNDERLAY_SIP1 = "55.1.2.3"
PL_UNDERLAY_SIP2 = "55.2.3.4"
Comment thread
theasianpianist marked this conversation as resolved.
Outdated
PL_OVERLAY_SIP = "fd41:108:20:abc:abc::0"
PL_OVERLAY_SIP_MASK = "ffff:ffff:ffff:ffff:ffff:ffff::"
PL_OVERLAY_DIP = "2603:10e1:100:2::3401:203"
PL_OVERLAY_DIP_MASK = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"

APPLIANCE_ID = "100"
VM_VNI = "4321"
ENCAP_VNI = 100
VNET1 = "Vnet1"
VNET1_VNI = "45654"
VNET1_GUID = "559c6ce8-26ab-4193-b946-ccc6e8f930b2"
ENI_MAC = "F4:93:9F:EF:C4:7E"
ENI_MAC_STRING = ENI_MAC.replace(":", "")
REMOTE_MAC = "43:BE:65:25:FA:67"
REMOTE_MAC_STRING = REMOTE_MAC.replace(":", "")
ENI_ID = "497f23d7-f0ac-4c99-a98f-59b470e8c7bd"
ROUTE_GROUP1 = "RouteGroup1"
ROUTE_GROUP2 = "RouteGroup2"
ROUTE_GROUP1_GUID = "48af6ce8-26cc-4293-bfa6-0126e8fcdeb2"
ROUTE_GROUP2_GUID = "58cf62e0-22cc-4693-baa6-012358fcdec9"

APPLIANCE_CONFIG = {
f"DASH_APPLIANCE_TABLE:{APPLIANCE_ID}":
ParseDict({
"sip": {
"ipv4": socket.htonl(int(IP(SIP)))
},
"vm_vni": int(VM_VNI)
}, Appliance())
}

VNET_CONFIG = {
f"DASH_VNET_TABLE:{VNET1}":
ParseDict({
"vni": VNET1_VNI,
"guid": {
"value": base64.b64encode(bytes.fromhex(uuid.UUID(VNET1_GUID).hex))
}
}, Vnet())
}

ENI_CONFIG = {
f"DASH_ENI_TABLE:{ENI_ID}":
ParseDict({
"vnet": VNET1,
"underlay_ip": {
"ipv4": socket.htonl(int(IP(INBOUND_UNDERLAY_IP)))
},
"mac_address": base64.b64encode(bytes.fromhex(ENI_MAC_STRING)),
"eni_id": ENI_ID,
"admin_state": State.STATE_ENABLED,
"pl_underlay_sip": {
"ipv4": socket.htonl(int(IP(PL_UNDERLAY_SIP1)))
},
"pl_sip_encoding": {
"ip": {
"ipv6": base64.b64encode(IP(PL_ENCODING_IP).packed)
},
"mask": {
"ipv6": base64.b64encode(IP(PL_ENCODING_MASK).packed)
}
}
}, Eni())
}

VNET_MAPPING_CONFIG = {
f"DASH_VNET_MAPPING_TABLE:{VNET1}:{VNET_MAP_IP1}":
ParseDict({
"mac_address": base64.b64encode(bytes.fromhex(REMOTE_MAC_STRING)),
"routing_type": RoutingType.ROUTING_TYPE_PRIVATELINK,
"underlay_ip": {
"ipv4": socket.htonl(int(IP(OUTBOUND_UNDERLAY_IP)))
},
"overlay_sip_prefix": {
"ip": {
"ipv6": base64.b64encode(IP(PL_OVERLAY_SIP).packed)
},
"mask": {
"ipv6": base64.b64encode(IP(PL_OVERLAY_SIP_MASK).packed)
}
},
"overlay_dip_prefix": {
"ip": {
"ipv6": base64.b64encode(IP(PL_OVERLAY_DIP).packed)
},
"mask": {
"ipv6": base64.b64encode(IP(PL_OVERLAY_DIP_MASK).packed)
}
},
}, VnetMapping())
}

ROUTE_VNET_CONFIG = {
f"DASH_ROUTE_TABLE:{ROUTE_GROUP1}:{OUTBOUND_ROUTE_PREFIX1}":
ParseDict({
"routing_type": RoutingType.ROUTING_TYPE_VNET,
"vnet": VNET1,
}, Route())
}

ROUTE_VNET_CONFIG_UNDERLAY_SIP = {
f"DASH_ROUTE_TABLE:{ROUTE_GROUP2}:{OUTBOUND_ROUTE_PREFIX2}":
ParseDict({
"routing_type": RoutingType.ROUTING_TYPE_VNET,
"vnet": VNET1,
"underlay_sip": {
"ipv4": socket.htonl(int(IP(PL_UNDERLAY_SIP2)))
}
}, Route())
}

ROUTING_TYPE_PL_CONFIG = {
f"DASH_ROUTING_TYPE_TABLE:{PRIVATELINK}":
ParseDict({
"items": [
{
"action_name": "action1",
"action_type": ActionType.ACTION_TYPE_4_to_6
},
{
"action_name": "action2",
"action_type": ActionType.ACTION_TYPE_STATICENCAP,
"encap_type": EncapType.ENCAP_TYPE_NVGRE,
"vni": ENCAP_VNI
}
]
}, RouteType())
}

ROUTE_GROUP1_CONFIG = {
f"DASH_ROUTE_GROUP_TABLE:{ROUTE_GROUP1}":
ParseDict({
"guid": ROUTE_GROUP1_GUID,
"version": "rg_version"
}, RouteGroup())
}

ENI_ROUTE_GROUP1_CONFIG = {
f"DASH_ENI_ROUTE_TABLE:{ENI_ID}":
ParseDict({
"group_id": ROUTE_GROUP1
}, EniRoute())
}
39 changes: 36 additions & 3 deletions tests/dash/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,36 @@ def get_intf_from_ip(local_ip, config_facts):
if str(intf_ip.ip) == local_ip:
return intf, intf_ip

for intf, config in list(config_facts["PORTCHANNEL_INTERFACE"].items()):
for ip in config:
intf_ip = ip_interface(ip)
if str(intf_ip.ip) == local_ip:
return intf, intf_ip


@pytest.fixture(params=["no-underlay-route", "with-underlay-route"])
def use_underlay_route(request):
return request.param == "with-underlay-route"


@pytest.fixture
def dash_pl_config(duthost, config_facts, minigraph_facts):
dash_info = {
DUT_MAC: config_facts["DEVICE_METADATA"]["localhost"]["mac"],
LOCAL_CA_IP: "10.2.2.2",
}

neigh_table = duthost.switch_arptable()['ansible_facts']['arptable']
for neigh_ip, config in list(config_facts["BGP_NEIGHBOR"].items()):
if ip_interface(neigh_ip).version == 4:
if config["name"].endswith("T0"):
intf, _ = get_intf_from_ip(config['local_addr'], config_facts)
dash_info[LOCAL_PTF_INTF] = minigraph_facts["minigraph_ptf_indices"][intf]
dash_info[LOCAL_PTF_MAC] = neigh_table["v4"][neigh_ip]["macaddress"]
break
return dash_info


@pytest.fixture(scope="function")
def dash_config_info(duthost, config_facts, minigraph_facts, tbinfo):
dash_info = {
Expand Down Expand Up @@ -148,11 +172,13 @@ def dash_config_info(duthost, config_facts, minigraph_facts, tbinfo):
# Take neighbor 1 as local PA, take neighbor 2 as remote PA
if ip_interface(neigh_ip).version == 4:
if LOCAL_PA_IP not in dash_info:
dash_info[LOCAL_PA_IP] = neigh_ip
intf, _ = get_intf_from_ip(config['local_addr'], config_facts)
if "PortChannel" in intf:
continue
dash_info[LOCAL_PA_IP] = neigh_ip
dash_info[LOCAL_PTF_INTF] = minigraph_facts["minigraph_ptf_indices"][intf]
dash_info[LOCAL_PTF_MAC] = neigh_table["v4"][neigh_ip]["macaddress"]
if topo == 'dpu-1' and REMOTE_PA_IP not in dash_info:
if (topo == 'dpu-1' or topo == "t1-28-lag") and REMOTE_PA_IP not in dash_info:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to add smartswitch-t1 topo as well here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll do this later. Ok to merge for now.

# For DPU with only one single port, we just have one neighbor (neighbor 1).
# So, we take neighbor 1 as the local PA. For the remote PA,
# we take the original neighbor 2's IP as the remote PA IP,
Expand All @@ -170,8 +196,10 @@ def dash_config_info(duthost, config_facts, minigraph_facts, tbinfo):
dash_info[REMOTE_PA_PREFIX] = fake_neighbor_2_prefix
break
elif REMOTE_PA_IP not in dash_info:
dash_info[REMOTE_PA_IP] = neigh_ip
intf, intf_ip = get_intf_from_ip(config['local_addr'], config_facts)
if "PortChannel" in intf:
continue
dash_info[REMOTE_PA_IP] = neigh_ip
dash_info[REMOTE_PTF_INTF] = minigraph_facts["minigraph_ptf_indices"][intf]
dash_info[REMOTE_PTF_MAC] = neigh_table["v4"][neigh_ip]["macaddress"]
dash_info[REMOTE_PA_PREFIX] = str(intf_ip.network)
Expand Down Expand Up @@ -354,3 +382,8 @@ def acl_default_rule(localhost, duthost, ptfhost, dash_config_info):
default_acl_rule.teardown()
del default_acl_group
time.sleep(WAIT_AFTER_CONFIG)


@pytest.fixture(scope="module")
def dpu_index():
return 0
50 changes: 45 additions & 5 deletions tests/dash/gnmi_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ def __init__(self, duthost):
self.gnmi_client_cert = "gnmiclient.crt"
self.gnmi_client_key = "gnmiclient.key"
self.gnmi_server_start_wait_time = 30
self.enable_zmq = duthost.shell("netstat -na | grep -w 8100", module_ignore_errors=True)['rc'] == 0
# self.enable_zmq = duthost.shell("netstat -na | grep -w 8100", module_ignore_errors=True)['rc'] == 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@theasianpianist , why change dash test case always enable ZMQ on GNMI?
If someone run these test case on a device not enable ZMQ on orchagent side, some test case may failed, can you check this change?

self.enable_zmq = True
cmd = "docker images | grep -w sonic-gnmi"
if duthost.shell(cmd, module_ignore_errors=True)['rc'] == 0:
cmd = "docker ps | grep -w gnmi"
Expand Down Expand Up @@ -267,6 +268,7 @@ def gnmi_set(duthost, ptfhost, delete_list, update_list, replace_list):
cmd += '--xpath ' + xpath
cmd += ' '
cmd += '--value ' + xvalue
logger.info(f"PTF GNMI command: {cmd}")
output = ptfhost.shell(cmd, module_ignore_errors=True)
error = "GRPC error\n"
if error in output['stdout']:
Expand Down Expand Up @@ -324,6 +326,40 @@ def gnmi_get(duthost, ptfhost, path_list):
raise Exception("error:" + msg)


def apply_messages(
localhost,
duthost,
ptfhost,
messages,
dpu_index,
set=True,
Comment thread
theasianpianist marked this conversation as resolved.
Outdated
wait_after_apply=5,
max_updates_in_single_cmd=1024,
):
env = GNMIEnvironment(duthost)
update_list = []
delete_list = []
for i, (key, message) in enumerate(messages.items()):
keys = key.split(":", 1)
k = keys[0] + "[key=" + keys[1] + "]"
filename = f"update{i}"

if set:
if proto_utils.ENABLE_PROTO:
path = f"/APPL_DB/dpu{dpu_index}/{k}:$/root/{filename}"
else:
path = f"/APPL_DB/dpu{dpu_index}/{k}:@/root/{filename}"
with open(env.work_dir + filename, "wb") as file:
file.write(message.SerializeToString())
update_list.append(path)
else:
path = f"/APPL_DB/dpu{dpu_index}/{filename}"
Comment thread
theasianpianist marked this conversation as resolved.
Outdated
delete_list.append(path)

write_gnmi_files(localhost, duthost, ptfhost, env, delete_list, update_list, max_updates_in_single_cmd)
time.sleep(wait_after_apply)


def apply_gnmi_file(localhost, duthost, ptfhost, dest_path=None, config_json=None,
wait_after_apply=5, max_updates_in_single_cmd=1024):
"""
Expand Down Expand Up @@ -371,20 +407,25 @@ def apply_gnmi_file(localhost, duthost, ptfhost, dest_path=None, config_json=Non
keys = k.split(":", 1)
k = keys[0] + "[key=" + keys[1] + "]"
if proto_utils.ENABLE_PROTO:
path = "/APPL_DB/localhost/%s:$/root/%s" % (k, filename)
path = "/APPL_DB/dpu1/%s:$/root/%s" % (k, filename)
else:
path = "/APPL_DB/localhost/%s:@/root/%s" % (k, filename)
path = "/APPL_DB/dpu1/%s:@/root/%s" % (k, filename)
Comment thread
theasianpianist marked this conversation as resolved.
update_list.append(path)
elif operation["OP"] == "DEL":
for k, v in operation.items():
if k == "OP":
continue
keys = k.split(":", 1)
k = keys[0] + "[key=" + keys[1] + "]"
path = "/APPL_DB/localhost/%s" % (k)
path = "/APPL_DB/dpu1/%s" % (k)
delete_list.append(path)
else:
logger.info("Invalid operation %s" % operation["OP"])
write_gnmi_files(localhost, duthost, ptfhost, env, delete_list, update_list, max_updates_in_single_cmd)
time.sleep(wait_after_apply)


def write_gnmi_files(localhost, duthost, ptfhost, env, delete_list, update_list, max_updates_in_single_cmd):
localhost.shell(f'tar -zcvf /tmp/updates.tar.gz -C {env.work_dir} .')
ptfhost.copy(src='/tmp/updates.tar.gz', dest='~')
ptfhost.shell('tar -xf updates.tar.gz')
Expand All @@ -410,4 +451,3 @@ def _devide_list(operation_list):
ptfhost.shell('rm -f updates.tar.gz')
localhost.shell(f'rm -f {env.work_dir}update*')
ptfhost.shell('rm -f update*')
time.sleep(wait_after_apply)
Loading