[caclmgrd]Added logic to allow BFD port numbers (#10735)

* [caclmgrd]Added logic to allow BFD port numbers
This commit is contained in:
Sudharsan Dhamal Gopalarathnam 2022-05-09 10:58:00 -07:00 committed by GitHub
parent 0ed671c9af
commit 0f6eb29460
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 117 additions and 15 deletions

View File

@ -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 = {
@ -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)
@ -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 = ""
@ -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
@ -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)
@ -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 = {}
@ -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:

View File

@ -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)

View File

@ -10,23 +10,21 @@ from pyfakefs.fake_filesystem_unittest import patchfs
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):
@ -46,7 +44,7 @@ class TestCaclmgrdDhcp(TestCase):
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:

View File

@ -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,
}
]
]