Skip to content

Commit 953816b

Browse files
authored
Modify cacl rules to allow incoming packets to dash-ha (#256)
why swbusd in dash-ha runs grpc client and server for connections within the switch and outside the switch. We need to config CACL iptables rules if dash-ha feature is enabled. what this PR does if dash-ha feature is enabled, subscribe to DPU table in config_db. Configure iptables based on the swbus_port in each DPU entries (up to 8). If swbus_port is changed, remove old iptables rules and add new rules. If DPU entry is deleted, remove corresponding iptables rules. how to verify Add dash-ha to feature table. "dash-ha": { "auto_restart": "disabled", "delayed": "False", "has_global_scope": "False", "has_per_asic_scope": "False", "has_per_dpu_scope": "True", "high_mem_alert": "disabled", "state": "enabled", "support_syslog_rate_limit": "true" } Add DPU table in config_db "DPU": { "dpu0": { "dpu_id": "0", "gnmi_port": "50051", "local_port": "8080", "orchagent_zmq_port": "5555", "pa_ipv4": "18.0.202.1", "state": "up", "swbus_port": "23606", "vdpu_id": "vdpu0", "vip_ipv4": "3.2.1.0" }, ... } verify iptables rule is created for both ipv4 and ipv6 to tcp port 23606. change swbus_port and verify old rules are removed and new rules are created.
1 parent 5460c29 commit 953816b

File tree

3 files changed

+186
-1
lines changed

3 files changed

+186
-1
lines changed

scripts/caclmgrd

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ class ControlPlaneAclManager(logger.Logger):
8585

8686
BFD_SESSION_TABLE = "BFD_SESSION_TABLE"
8787
VXLAN_TUNNEL_TABLE = "VXLAN_TUNNEL"
88+
DPU_TABLE = "DPU"
8889

8990
# To specify a port range instead of a single port, use iptables format:
9091
# separate start and end ports with a colon, e.g., "1000:2000"
@@ -121,7 +122,9 @@ class ControlPlaneAclManager(logger.Logger):
121122
bfdAllowed = False
122123
VxlanAllowed = False
123124
VxlanSrcIP = ""
124-
125+
# a map from dpu name to port
126+
dashHaPortMap = {}
127+
125128
def __init__(self, log_identifier):
126129
super(ControlPlaneAclManager, self).__init__(log_identifier)
127130

@@ -601,6 +604,10 @@ class ControlPlaneAclManager(logger.Logger):
601604
fvs = swsscommon.FieldValuePairs([("src_ip", self.VxlanSrcIP)])
602605
iptables_cmds += self.get_vxlan_port_iptable_commands(namespace, fvs)
603606

607+
for dpu, port in self.dashHaPortMap.items():
608+
iptables_cmds += self.make_dash_ha_rules(namespace, port)
609+
self.log_info(f"Enabled dash-ha port {port} for {dpu}")
610+
604611
# Add iptables commands to allow internal docker traffic
605612
iptables_cmds += self.generate_allow_internal_docker_ip_traffic_commands(namespace)
606613

@@ -972,6 +979,58 @@ class ControlPlaneAclManager(logger.Logger):
972979
self.VxlanSrcIP = ""
973980
return True
974981

982+
def remove_dash_ha_rules(self, namespace, port):
983+
iptables_cmds = []
984+
# Remove iptables/ip6tables commands that allow DASH-HA packets
985+
iptables_cmds.append(self.iptables_cmd_ns_prefix[namespace] +
986+
['iptables', '-D', 'INPUT', '-p', 'tcp', '--dport', str(port), '-j', 'ACCEPT'])
987+
iptables_cmds.append(self.iptables_cmd_ns_prefix[namespace] +
988+
['ip6tables', '-D', 'INPUT', '-p', 'tcp', '--dport', str(port), '-j', 'ACCEPT'])
989+
self.run_commands(iptables_cmds)
990+
991+
def add_dash_ha_rules(self, namespace, port):
992+
iptables_cmds = self.make_dash_ha_rules(namespace, port)
993+
self.run_commands(iptables_cmds)
994+
995+
def make_dash_ha_rules(self, namespace, port):
996+
iptables_cmds = []
997+
# make iptables/ip6tables commands that allow DASH-HA packets
998+
iptables_cmds.append(self.iptables_cmd_ns_prefix[namespace] +
999+
['iptables', '-I', 'INPUT', '2', '-p', 'tcp', '--dport', str(port), '-j', 'ACCEPT'])
1000+
iptables_cmds.append(self.iptables_cmd_ns_prefix[namespace] +
1001+
['ip6tables', '-I', 'INPUT', '2', '-p', 'tcp', '--dport', str(port), '-j', 'ACCEPT'])
1002+
return iptables_cmds
1003+
1004+
def update_dash_ha_rules(self, namespace, key, op, data):
1005+
port = self.dashHaPortMap.get(key)
1006+
if op == "DEL" and not port:
1007+
return
1008+
1009+
if op == "DEL" and port:
1010+
# Remove iptables/ip6tables commands that allow DASH-HA packets
1011+
self.remove_dash_ha_rules(namespace, port)
1012+
self.dashHaPortMap.pop(key)
1013+
return
1014+
1015+
if op == "SET":
1016+
new_port = None
1017+
for fv in data:
1018+
if (fv[0] == "swbus_port"):
1019+
new_port = fv[1]
1020+
break
1021+
if not new_port:
1022+
self.log_info("Received DPU configuration without swbus_port. Ignore it.")
1023+
return
1024+
if new_port == port:
1025+
return
1026+
if port:
1027+
# Remove iptables/ip6tables commands that allow DASH-HA packets
1028+
self.remove_dash_ha_rules(namespace, port)
1029+
# Add iptables/ip6tables commands to allow DASH-HA packets
1030+
self.add_dash_ha_rules(namespace, new_port)
1031+
self.dashHaPortMap[key] = new_port
1032+
return
1033+
9751034
def run(self):
9761035
# Set select timeout to 1 second
9771036
SELECT_TIMEOUT_MS = 1000
@@ -1022,6 +1081,9 @@ class ControlPlaneAclManager(logger.Logger):
10221081

10231082
subscribe_vxlan_table = swsscommon.SubscriberStateTable(config_db_connector, self.VXLAN_TUNNEL_TABLE)
10241083
sel.addSelectable(subscribe_vxlan_table)
1084+
1085+
subscribe_dpu_table = swsscommon.SubscriberStateTable(config_db_connector, self.DPU_TABLE)
1086+
sel.addSelectable(subscribe_dpu_table)
10251087
# Map of Namespace <--> susbcriber table's object
10261088
config_db_subscriber_table_map = {}
10271089

@@ -1106,6 +1168,13 @@ class ControlPlaneAclManager(logger.Logger):
11061168
elif op == 'DEL' and self.VxlanAllowed:
11071169
self.block_vxlan_port(namespace)
11081170

1171+
while True:
1172+
key, op, fvs = subscribe_dpu_table.pop()
1173+
if not key:
1174+
break
1175+
if "dash-ha" in self.feature_present:
1176+
self.update_dash_ha_rules(namespace, key, op, fvs)
1177+
11091178
ctrl_plane_acl_notification = set()
11101179

11111180
# Pop data of both Subscriber Table object of namespace that got config db acl table event
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import os
2+
import sys
3+
from swsscommon import swsscommon
4+
5+
from parameterized import parameterized
6+
from sonic_py_common.general import load_module_from_source
7+
from unittest import TestCase, mock
8+
from pyfakefs.fake_filesystem_unittest import patchfs
9+
10+
from .test_dash_ha_vectors import CACLMGRD_DASH_HA_TEST_VECTOR
11+
from tests.common.mock_configdb import MockConfigDb
12+
from unittest.mock import MagicMock, patch
13+
14+
DBCONFIG_PATH = '/var/run/redis/sonic-db/database_config.json'
15+
16+
class TestCaclmgrdDashHa(TestCase):
17+
"""
18+
Test caclmgrd bfd
19+
"""
20+
def setUp(self):
21+
swsscommon.ConfigDBConnector = MockConfigDb
22+
test_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
23+
modules_path = os.path.dirname(test_path)
24+
scripts_path = os.path.join(modules_path, "scripts")
25+
sys.path.insert(0, modules_path)
26+
caclmgrd_path = os.path.join(scripts_path, 'caclmgrd')
27+
self.caclmgrd = load_module_from_source('caclmgrd', caclmgrd_path)
28+
29+
@parameterized.expand(CACLMGRD_DASH_HA_TEST_VECTOR)
30+
@patchfs
31+
def test_caclmgrd_dash_ha(self, test_name, test_data, fs):
32+
if not os.path.exists(DBCONFIG_PATH):
33+
fs.create_file(DBCONFIG_PATH) # fake database_config.json
34+
35+
MockConfigDb.set_config_db(test_data["config_db"])
36+
37+
with mock.patch("caclmgrd.ControlPlaneAclManager.run_commands_pipe", return_value='sonic'):
38+
with mock.patch("caclmgrd.subprocess") as mocked_subprocess:
39+
popen_mock = mock.Mock()
40+
popen_attrs = test_data["popen_attributes"]
41+
popen_mock.configure_mock(**popen_attrs)
42+
mocked_subprocess.Popen.return_value = popen_mock
43+
mocked_subprocess.PIPE = -1
44+
45+
call_rc = test_data["call_rc"]
46+
mocked_subprocess.call.return_value = call_rc
47+
48+
caclmgrd_daemon = self.caclmgrd.ControlPlaneAclManager("caclmgrd")
49+
assert(caclmgrd_daemon.feature_present["dash-ha"] == True)
50+
# a set operation without swbus_port. It is no-op.
51+
caclmgrd_daemon.update_dash_ha_rules('', "dpu0", "SET", ["somekey", "somevalue"])
52+
53+
caclmgrd_daemon.update_dash_ha_rules('', "dpu0", "SET", test_data["input_add"])
54+
mocked_subprocess.Popen.assert_has_calls(test_data["expected_add_subprocess_calls"], any_order=True)
55+
56+
caclmgrd_daemon.update_dash_ha_rules('', "dpu0", "SET", test_data["input_upd"])
57+
mocked_subprocess.Popen.assert_has_calls(test_data["expected_upd_subprocess_calls"], any_order=True)
58+
59+
caclmgrd_daemon.update_dash_ha_rules('', "dpu0", "DEL", {})
60+
mocked_subprocess.Popen.assert_has_calls(test_data["expected_del_subprocess_calls"], any_order=True)
61+
62+
caclmgrd_daemon.update_dash_ha_rules('', "dpu0", "SET", test_data["input_add"])
63+
mocked_subprocess.Popen.reset_mock()
64+
caclmgrd_daemon.num_changes[''] = 1
65+
caclmgrd_daemon.check_and_update_control_plane_acls('', 1)
66+
mocked_subprocess.Popen.assert_has_calls(test_data["expected_add_subprocess_calls"], any_order=True)
67+
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
from unittest.mock import call
2+
import subprocess
3+
4+
"""
5+
caclmgrd dash-ha test vector
6+
"""
7+
CACLMGRD_DASH_HA_TEST_VECTOR = [
8+
[
9+
"DASH_HA_TEST",
10+
{
11+
"config_db": {
12+
"DEVICE_METADATA": {
13+
"localhost": {
14+
"subtype": "SmartSwitch",
15+
"type": "LeafRouter",
16+
}
17+
},
18+
"FEATURE": {
19+
"dash-ha": {
20+
"auto_restart": "enabled",
21+
"has_per_dpu_scope": "True",
22+
"state": "enabled",
23+
}
24+
}
25+
},
26+
"input_add" : [("swbus_port", "23606")],
27+
"input_upd" : [("swbus_port", "23607")],
28+
"expected_add_subprocess_calls": [
29+
call(['iptables', '-I', 'INPUT', '2', '-p', 'tcp', '--dport', '23606', '-j', 'ACCEPT'], universal_newlines=True, stdout=subprocess.PIPE),
30+
call(['ip6tables', '-I', 'INPUT', '2', '-p', 'tcp', '--dport', '23606', '-j', 'ACCEPT'], universal_newlines=True, stdout=subprocess.PIPE),
31+
],
32+
"expected_upd_subprocess_calls": [
33+
call(['iptables', '-D', 'INPUT', '-p', 'tcp', '--dport', '23606', '-j', 'ACCEPT'], universal_newlines=True, stdout=subprocess.PIPE),
34+
call(['ip6tables', '-D', 'INPUT', '-p', 'tcp', '--dport', '23606', '-j', 'ACCEPT'], universal_newlines=True, stdout=subprocess.PIPE),
35+
call(['iptables', '-I', 'INPUT', '2', '-p', 'tcp', '--dport', '23607', '-j', 'ACCEPT'], universal_newlines=True, stdout=subprocess.PIPE),
36+
call(['ip6tables', '-I', 'INPUT', '2', '-p', 'tcp', '--dport', '23607', '-j', 'ACCEPT'], universal_newlines=True, stdout=subprocess.PIPE),
37+
],
38+
"expected_del_subprocess_calls": [
39+
call(['iptables', '-D', 'INPUT', '-p', 'tcp', '--dport', '23607', '-j', 'ACCEPT'], universal_newlines=True, stdout=subprocess.PIPE),
40+
call(['ip6tables', '-D', 'INPUT', '-p', 'tcp', '--dport', '23607', '-j', 'ACCEPT'], universal_newlines=True, stdout=subprocess.PIPE),
41+
],
42+
43+
"popen_attributes": {
44+
'communicate.return_value': ('output', 'error'),
45+
},
46+
"call_rc": 0,
47+
}
48+
]
49+
]

0 commit comments

Comments
 (0)