Skip to content

Commit

Permalink
caclmgrd: support packet mark in DHCP chain (#9191)
Browse files Browse the repository at this point in the history
* caclmgrd:support packet mark in DCHP chain
  • Loading branch information
trzhang-msft authored Nov 8, 2021
1 parent baa00e6 commit 7e8ebaa
Show file tree
Hide file tree
Showing 3 changed files with 215 additions and 18 deletions.
63 changes: 53 additions & 10 deletions src/sonic-host-services/scripts/caclmgrd
Original file line number Diff line number Diff line change
Expand Up @@ -359,16 +359,20 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):

return chain_list

def dhcp_acl_rule(self, iptable_ns_cmd_prefix, op, intf):
def dhcp_acl_rule(self, iptable_ns_cmd_prefix, op, intf, mark):
'''
sample: iptables --insert/delete/check DHCP -m physdev --physdev-in Ethernet4 -j DROP
sample: iptables --insert/delete/check DHCP -m mark --mark 0x67004 -j DROP
'''
return iptable_ns_cmd_prefix + 'iptables --{} DHCP -m physdev --physdev-in {} -j DROP'.format(op, intf)
if mark is None:
return iptable_ns_cmd_prefix + 'iptables --{} DHCP -m physdev --physdev-in {} -j DROP'.format(op, intf)
else:
return iptable_ns_cmd_prefix + 'iptables --{} DHCP -m mark --mark {} -j DROP'.format(op, mark)

def update_dhcp_chain(self, op, intf):
def update_dhcp_chain(self, op, intf, mark):
for namespace in list(self.config_db_map.keys()):
check_cmd = self.dhcp_acl_rule(self.iptables_cmd_ns_prefix[namespace], "check", intf)
update_cmd = self.dhcp_acl_rule(self.iptables_cmd_ns_prefix[namespace], op, intf)
check_cmd = self.dhcp_acl_rule(self.iptables_cmd_ns_prefix[namespace], "check", intf, mark)
update_cmd = self.dhcp_acl_rule(self.iptables_cmd_ns_prefix[namespace], op, intf, mark)

execute = 0
ret = subprocess.call(check_cmd, shell=True) # ret==0 indicates the rule exists
Expand All @@ -382,7 +386,7 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
subprocess.call(update_cmd, shell=True)
self.log_info("Update DHCP chain: {}".format(update_cmd))

def update_dhcp_acl(self, key, op, data):
def update_dhcp_acl(self, key, op, data, mark):
if "state" not in data:
self.log_warning("Unexpected update in MUX_CABLE_TABLE")
return
Expand All @@ -391,16 +395,33 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
state = data["state"]

if state == "active":
self.update_dhcp_chain("delete", intf)
self.update_dhcp_chain("delete", intf, mark)
elif state == "standby":
self.update_dhcp_chain("insert", intf)
self.update_dhcp_chain("insert", intf, mark)
elif state == "unknown":
self.update_dhcp_chain("delete", intf)
self.update_dhcp_chain("delete", intf, mark)
elif state == "error":
self.log_warning("Cable state shows error")
else:
self.log_warning("Unexpected cable state")

def update_dhcp_acl_for_mark_change(self, key, pre_mark, cur_mark):
for namespace in list(self.config_db_map.keys()):
check_cmd = self.dhcp_acl_rule(self.iptables_cmd_ns_prefix[namespace], "check", key, pre_mark)

ret = subprocess.call(check_cmd, shell=True) # ret==0 indicates the rule exists

'''update only when the rule with pre_mark exists'''
if ret == 0:
delete_cmd = self.dhcp_acl_rule(self.iptables_cmd_ns_prefix[namespace], "delete", key, pre_mark)
insert_cmd = self.dhcp_acl_rule(self.iptables_cmd_ns_prefix[namespace], "insert", key, cur_mark)

subprocess.call(delete_cmd, shell=True)
self.log_info("Update DHCP chain: {}".format(delete_cmd))
subprocess.call(insert_cmd, shell=True)
self.log_info("Update DHCP chain: {}".format(insert_cmd))


def get_acl_rules_and_translate_to_iptables_commands(self, namespace):
"""
Retrieves current ACL tables and rules from Config DB, translates
Expand Down Expand Up @@ -708,16 +729,22 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
# Set up STATE_DB connector to monitor the change in MUX_CABLE_TABLE
state_db_connector = None
subscribe_mux_cable = None
subscribe_dhcp_packet_mark = None
state_db_id = swsscommon.SonicDBConfig.getDbId("STATE_DB")
dhcp_packet_mark_tbl = {}

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)

subscribe_dhcp_packet_mark = swsscommon.SubscriberStateTable(state_db_connector, "DHCP_PACKET_MARK")
sel.addSelectable(subscribe_dhcp_packet_mark)

# create DHCP chain
for namespace in list(self.config_db_map.keys()):
self.setup_dhcp_chain(namespace)
Expand Down Expand Up @@ -762,12 +789,28 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):

if db_id == state_db_id:
if self.DualToR:
'''dhcp packet mark update'''
while True:
key, op, fvs = subscribe_dhcp_packet_mark.pop()
if not key:
break
self.log_info("dhcp packet mark update : '%s'" % str((key, op, fvs)))

'''initial value is None'''
pre_mark = None if key not in dhcp_packet_mark_tbl else dhcp_packet_mark_tbl[key]
cur_mark = None if op == 'DEL' else dict(fvs)['mark']
dhcp_packet_mark_tbl[key] = cur_mark
self.update_dhcp_acl_for_mark_change(key, pre_mark, cur_mark)

'''mux cable update'''
while True:
key, op, fvs = subscribe_mux_cable.pop()
if not key:
break
self.log_info("mux cable update : '%s'" % str((key, op, fvs)))
self.update_dhcp_acl(key, op, dict(fvs))

mark = None if key not in dhcp_packet_mark_tbl else dhcp_packet_mark_tbl[key]
self.update_dhcp_acl(key, op, dict(fvs), mark)
continue

ctrl_plane_acl_notification = set()
Expand Down
5 changes: 3 additions & 2 deletions src/sonic-host-services/tests/caclmgrd/caclmgrd_dhcp_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,15 @@ def test_caclmgrd_dhcp(self, test_name, test_data, fs):
popen_mock.configure_mock(**popen_attrs)
mocked_subprocess.Popen.return_value = popen_mock

call_mock = mock.Mock()
call_rc = test_data["call_rc"]
mocked_subprocess.call.return_value = call_rc

mark = test_data["mark"]

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

for key,data in mux_update:
caclmgrd_daemon.update_dhcp_acl(key, '', data)
caclmgrd_daemon.update_dhcp_acl(key, '', data, mark)

mocked_subprocess.call.assert_has_calls(test_data["expected_subprocess_calls"], any_order=False)
165 changes: 159 additions & 6 deletions src/sonic-host-services/tests/caclmgrd/test_dhcp_vectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""
CACLMGRD_DHCP_TEST_VECTOR = [
[
"Active_Present",
"Active_Present_Interface",
{
"config_db": {
"DEVICE_METADATA": {
Expand All @@ -29,10 +29,36 @@
'communicate.return_value': ('output', 'error'),
},
"call_rc": 0,
"mark": None,
},
],
[
"Active_Absent",
"Active_Present_Mark",
{
"config_db": {
"DEVICE_METADATA": {
"localhost": {
"subtype": "DualToR",
"type": "ToRRouter",
}
},
},
"mux_update": [
("Ethernet4", {"state": "active"}),
],
"expected_subprocess_calls": [
call("iptables --check DHCP -m mark --mark 0x67004 -j DROP", shell=True),
call("iptables --delete DHCP -m mark --mark 0x67004 -j DROP", shell=True),
],
"popen_attributes": {
'communicate.return_value': ('output', 'error'),
},
"call_rc": 0,
"mark": "0x67004",
},
],
[
"Active_Absent_Interface",
{
"config_db": {
"DEVICE_METADATA": {
Expand All @@ -54,10 +80,35 @@
'communicate.return_value': ('output', 'error'),
},
"call_rc": 1,
"mark": None,
},
],
[
"Standby_Present",
"Active_Absent_Mark",
{
"config_db": {
"DEVICE_METADATA": {
"localhost": {
"subtype": "DualToR",
"type": "ToRRouter",
}
},
},
"mux_update": [
("Ethernet4", {"state": "active"}),
],
"expected_subprocess_calls": [
call("iptables --check DHCP -m mark --mark 0x67004 -j DROP", shell=True),
],
"popen_attributes": {
'communicate.return_value': ('output', 'error'),
},
"call_rc": 1,
"mark": "0x67004",
},
],
[
"Standby_Present_Interface",
{
"config_db": {
"DEVICE_METADATA": {
Expand All @@ -79,10 +130,35 @@
'communicate.return_value': ('output', 'error'),
},
"call_rc": 0,
"mark": None,
},
],
[
"Standby_Present_Mark",
{
"config_db": {
"DEVICE_METADATA": {
"localhost": {
"subtype": "DualToR",
"type": "ToRRouter",
}
},
},
"mux_update": [
("Ethernet4", {"state": "standby"}),
],
"expected_subprocess_calls": [
call("iptables --check DHCP -m mark --mark 0x67004 -j DROP", shell=True),
],
"popen_attributes": {
'communicate.return_value': ('output', 'error'),
},
"call_rc": 0,
"mark": "0x67004",
},
],
[
"Standby_Absent",
"Standby_Absent_Interface",
{
"config_db": {
"DEVICE_METADATA": {
Expand All @@ -106,10 +182,36 @@
'communicate.return_value': ('output', 'error'),
},
"call_rc": 1,
"mark": None,
},
],
[
"Unknown_Present",
"Standby_Absent_Mark",
{
"config_db": {
"DEVICE_METADATA": {
"localhost": {
"subtype": "DualToR",
"type": "ToRRouter",
}
},
},
"mux_update": [
("Ethernet4", {"state": "standby"}),
],
"expected_subprocess_calls": [
call("iptables --check DHCP -m mark --mark 0x67004 -j DROP", shell=True),
call("iptables --insert DHCP -m mark --mark 0x67004 -j DROP", shell=True),
],
"popen_attributes": {
'communicate.return_value': ('output', 'error'),
},
"call_rc": 1,
"mark": "0x67004",
},
],
[
"Unknown_Present_Interface",
{
"config_db": {
"DEVICE_METADATA": {
Expand All @@ -133,10 +235,36 @@
'communicate.return_value': ('output', 'error'),
},
"call_rc": 0,
"mark": None,
},
],
[
"Uknown_Absent",
"Unknown_Present_Mark",
{
"config_db": {
"DEVICE_METADATA": {
"localhost": {
"subtype": "DualToR",
"type": "ToRRouter",
}
},
},
"mux_update": [
("Ethernet4", {"state": "unknown"}),
],
"expected_subprocess_calls": [
call("iptables --check DHCP -m mark --mark 0x67004 -j DROP", shell=True),
call("iptables --delete DHCP -m mark --mark 0x67004 -j DROP", shell=True),
],
"popen_attributes": {
'communicate.return_value': ('output', 'error'),
},
"call_rc": 0,
"mark": "0x67004",
},
],
[
"Uknown_Absent_Interface",
{
"config_db": {
"DEVICE_METADATA": {
Expand All @@ -158,6 +286,31 @@
'communicate.return_value': ('output', 'error'),
},
"call_rc": 1,
"mark": None,
},
],
[
"Uknown_Absent_Mark",
{
"config_db": {
"DEVICE_METADATA": {
"localhost": {
"subtype": "DualToR",
"type": "ToRRouter",
}
},
},
"mux_update": [
("Ethernet4", {"state": "unknown"}),
],
"expected_subprocess_calls": [
call("iptables --check DHCP -m mark --mark 0x67004 -j DROP", shell=True),
],
"popen_attributes": {
'communicate.return_value': ('output', 'error'),
},
"call_rc": 1,
"mark": "0x67004",
},
],
]

0 comments on commit 7e8ebaa

Please sign in to comment.