Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
31 changes: 28 additions & 3 deletions src/sonic-host-services/scripts/caclmgrd
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):

ACL_TABLE_TYPE_CTRLPLANE = "CTRLPLANE"

BFD_SESSION_TABLE = "BFD_SESSION_TABLE"

# To specify a port range instead of a single port, use iptables format:
# separate start and end ports with a colon, e.g., "1000:2000"
ACL_SERVICES = {
Expand Down Expand Up @@ -87,6 +89,7 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
UPDATE_DELAY_SECS = 0.5

DualToR = False
bfdAllowed = False

def __init__(self, log_identifier):
super(ControlPlaneAclManager, self).__init__(log_identifier)
Expand Down Expand Up @@ -170,6 +173,7 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
self.log_error("Error running command '{}'".format(cmd))
elif stdout:
return stdout.rstrip('\n')
return ""

def parse_int_to_tcp_flags(self, hex_value):
tcp_flags_str = ""
Expand Down Expand Up @@ -705,6 +709,13 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
self.update_thread[namespace] = None
return

def allow_bfd_protocol(self, namespace):
iptables_cmds = []
# Add iptables/ip6tables commands to allow all BFD singlehop and multihop sessions
iptables_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -I INPUT 2 -p udp -m multiport --dports 3784,4784 -j ACCEPT")
iptables_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -I INPUT 2 -p udp -m multiport --dports 3784,4784 -j ACCEPT")
self.run_commands(iptables_cmds)

def run(self):
# Set select timeout to 1 second
SELECT_TIMEOUT_MS = 1000
Expand All @@ -730,12 +741,12 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
state_db_id = swsscommon.SonicDBConfig.getDbId("STATE_DB")
dhcp_packet_mark_tbl = {}

# set up state_db connector
state_db_connector = swsscommon.DBConnector("STATE_DB", 0)

if self.DualToR:
self.log_info("Dual ToR mode")

# set up state_db connector
state_db_connector = swsscommon.DBConnector("STATE_DB", 0)

subscribe_mux_cable = swsscommon.SubscriberStateTable(state_db_connector, self.MUX_CABLE_TABLE)
sel.addSelectable(subscribe_mux_cable)

Expand All @@ -746,6 +757,10 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
for namespace in list(self.config_db_map.keys()):
self.setup_dhcp_chain(namespace)

# This should be migrated from state_db BFD session table to feature_table in the future when feature table support gets added for BFD
subscribe_bfd_session = swsscommon.SubscriberStateTable(state_db_connector, self.BFD_SESSION_TABLE)
sel.addSelectable(subscribe_bfd_session)

# Map of Namespace <--> susbcriber table's object
config_db_subscriber_table_map = {}

Expand Down Expand Up @@ -785,6 +800,16 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
db_id = redisSelectObj.getDbConnector().getDbId()

if db_id == state_db_id:
while True:
key, op, fvs = subscribe_bfd_session.pop()
if not key:
break

if op == 'SET' and not self.bfdAllowed:
self.allow_bfd_protocol(namespace)
self.bfdAllowed = True
sel.removeSelectable(subscribe_bfd_session)

if self.DualToR:
'''dhcp packet mark update'''
while True:
Expand Down
50 changes: 50 additions & 0 deletions src/sonic-host-services/tests/caclmgrd/caclmgrd_bfd_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import os
import sys
import swsscommon

from parameterized import parameterized
from sonic_py_common.general import load_module_from_source
from unittest import TestCase, mock
from pyfakefs.fake_filesystem_unittest import patchfs

from .test_bfd_vectors import CACLMGRD_BFD_TEST_VECTOR
from tests.common.mock_configdb import MockConfigDb
from unittest.mock import MagicMock, patch

DBCONFIG_PATH = '/var/run/redis/sonic-db/database_config.json'

class TestCaclmgrdBfd(TestCase):
"""
Test caclmgrd bfd
"""
def setUp(self):
swsscommon.swsscommon.ConfigDBConnector = MockConfigDb
test_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
modules_path = os.path.dirname(test_path)
scripts_path = os.path.join(modules_path, "scripts")
sys.path.insert(0, modules_path)
caclmgrd_path = os.path.join(scripts_path, 'caclmgrd')
self.caclmgrd = load_module_from_source('caclmgrd', caclmgrd_path)

@parameterized.expand(CACLMGRD_BFD_TEST_VECTOR)
@patchfs
def test_caclmgrd_bfd(self, test_name, test_data, fs):
if not os.path.exists(DBCONFIG_PATH):
fs.create_file(DBCONFIG_PATH) # fake database_config.json

MockConfigDb.set_config_db(test_data["config_db"])

with mock.patch("caclmgrd.subprocess") as mocked_subprocess:
popen_mock = mock.Mock()
popen_attrs = test_data["popen_attributes"]
popen_mock.configure_mock(**popen_attrs)
mocked_subprocess.Popen.return_value = popen_mock
mocked_subprocess.PIPE = -1

call_rc = test_data["call_rc"]
mocked_subprocess.call.return_value = call_rc

caclmgrd_daemon = self.caclmgrd.ControlPlaneAclManager("caclmgrd")
caclmgrd_daemon.allow_bfd_protocol('')
mocked_subprocess.Popen.assert_has_calls(test_data["expected_subprocess_calls"], any_order=True)

22 changes: 10 additions & 12 deletions src/sonic-host-services/tests/caclmgrd/caclmgrd_dhcp_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,21 @@
from .test_dhcp_vectors import CACLMGRD_DHCP_TEST_VECTOR
from tests.common.mock_configdb import MockConfigDb


DBCONFIG_PATH = '/var/run/redis/sonic-db/database_config.json'


swsscommon.swsscommon.ConfigDBConnector = MockConfigDb
test_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
modules_path = os.path.dirname(test_path)
scripts_path = os.path.join(modules_path, "scripts")
sys.path.insert(0, modules_path)
caclmgrd_path = os.path.join(scripts_path, 'caclmgrd')
caclmgrd = load_module_from_source('caclmgrd', caclmgrd_path)


class TestCaclmgrdDhcp(TestCase):
"""
Test caclmgrd dhcp
"""
def setUp(self):
swsscommon.ConfigDBConnector = MockConfigDb
test_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
modules_path = os.path.dirname(test_path)
scripts_path = os.path.join(modules_path, "scripts")
sys.path.insert(0, modules_path)
caclmgrd_path = os.path.join(scripts_path, 'caclmgrd')
self.caclmgrd = load_module_from_source('caclmgrd', caclmgrd_path)

@parameterized.expand(CACLMGRD_DHCP_TEST_VECTOR)
@patchfs
def test_caclmgrd_dhcp(self, test_name, test_data, fs):
Expand All @@ -46,7 +44,7 @@ def test_caclmgrd_dhcp(self, test_name, test_data, fs):

mark = test_data["mark"]

caclmgrd_daemon = caclmgrd.ControlPlaneAclManager("caclmgrd")
caclmgrd_daemon = self.caclmgrd.ControlPlaneAclManager("caclmgrd")
mux_update = test_data["mux_update"]

for key,data in mux_update:
Expand Down
29 changes: 29 additions & 0 deletions src/sonic-host-services/tests/caclmgrd/test_bfd_vectors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from unittest.mock import call
import subprocess

"""
caclmgrd bfd test vector
"""
CACLMGRD_BFD_TEST_VECTOR = [
[
"BFD_SESSION_TEST",
{
"config_db": {
"DEVICE_METADATA": {
"localhost": {
"subtype": "DualToR",
"type": "ToRRouter",
}
},
},
"expected_subprocess_calls": [
call("iptables -I INPUT 2 -p udp -m multiport --dports 3784,4784 -j ACCEPT", shell=True, universal_newlines=True, stdout=subprocess.PIPE),
call("ip6tables -I INPUT 2 -p udp -m multiport --dports 3784,4784 -j ACCEPT", shell=True, universal_newlines=True, stdout=subprocess.PIPE)
],
"popen_attributes": {
'communicate.return_value': ('output', 'error'),
},
"call_rc": 0,
}
]
]