Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[caclmgrd] Add support for multi-ASIC platforms #5022

Merged
merged 16 commits into from
Aug 20, 2020
Merged
Changes from 1 commit
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
49 changes: 24 additions & 25 deletions files/image_config/caclmgrd/caclmgrd
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ try:
import subprocess
import sys
import syslog

import sonic_device_util
jleveque marked this conversation as resolved.
Show resolved Hide resolved
abdosi marked this conversation as resolved.
Show resolved Hide resolved
from swsscommon import swsscommon
from swsssdk import SonicDBConfig, ConfigDBConnector
Expand Down Expand Up @@ -49,6 +49,7 @@ def log_error(msg):

# ========================== Helper Functions =========================


def _ip_prefix_in_key(key):
"""
Function to check if IP prefix is present in a Redis database key.
Expand All @@ -59,12 +60,12 @@ def _ip_prefix_in_key(key):

# ============================== Classes ==============================


class ControlPlaneAclManager(object):
"""
Class which reads control plane ACL tables and rules from Config DB,
translates them into equivalent iptables commands and runs those
commands in order to apply the control plane ACLs.

Attributes:
config_db: Handle to Config Redis database via SwSS SDK
"""
Expand Down Expand Up @@ -104,15 +105,15 @@ class ControlPlaneAclManager(object):
self.config_db_map[front_asic_namespaces] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces)
self.config_db_map[front_asic_namespaces].connect()
self.iptables_cmd_ns_prefix[front_asic_namespaces] = "ip netns exec " + front_asic_namespaces + " "
self.namespace_docker_mgmt_ip[front_asic_namespaces] = self.get_docker_ip_address(self.iptables_cmd_ns_prefix[front_asic_namespaces],
front_asic_namespaces)
self.namespace_docker_mgmt_ip[front_asic_namespaces] = self.get_docker_ip_address(self.iptables_cmd_ns_prefix[front_asic_namespaces],
front_asic_namespaces)

for back_asic_namespaces in namespaces['back_ns']:
jleveque marked this conversation as resolved.
Show resolved Hide resolved
self.iptables_cmd_ns_prefix[back_asic_namespaces] = "ip netns exec " + back_asic_namespaces + " "
self.namespace_docker_mgmt_ip[back_asic_namespaces] = self.get_docker_ip_address(self.iptables_cmd_ns_prefix[back_asic_namespaces],
back_asic_namespaces)

def get_docker_ip_address(self, iptable_ns_cmd_prefix, namespace):
jleveque marked this conversation as resolved.
Show resolved Hide resolved

ip_address_get_command = iptable_ns_cmd_prefix + "ip -4 -o addr show " + ("eth0" if namespace else "docker0") +\
" | awk '{print $4}' | cut -d'/' -f1 | head -1"

Expand All @@ -121,7 +122,6 @@ class ControlPlaneAclManager(object):
def run_commands(self, commands):
"""
Given a list of shell commands, run them in order

Args:
commands: List of strings, each string is a shell command
"""
Expand Down Expand Up @@ -198,34 +198,34 @@ class ControlPlaneAclManager(object):

def generate_allow_internal_docker_ip_traffic_commands(self, namespace):
jleveque marked this conversation as resolved.
Show resolved Hide resolved
allow_internal_docker_ip_cmds = []

if namespace:
# For namespace docker allow all tcp/udp traffic from host docker bridge to its eth0 management ip
allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -p tcp -s {} -d {} -j ACCEPT".format\
allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -p tcp -s {} -d {} -j ACCEPT".format
(self.docker_bridge_ip, self.namespace_docker_mgmt_ip[namespace]))

allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -p udp -s {} -d {} -j ACCEPT".format\
allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -p udp -s {} -d {} -j ACCEPT".format
(self.docker_bridge_ip, self.namespace_docker_mgmt_ip[namespace]))
else:
# In host allow all tcp/udp traffic from namespace docker eth0 management ip to host docker bridge
for docker_mgmt_ip in self.namespace_docker_mgmt_ip.values():
allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -p tcp -s {} -d {} -j ACCEPT".format\
(docker_mgmt_ip, self.docker_bridge_ip))
allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -p tcp -s {} -d {} -j ACCEPT".format
(docker_mgmt_ip, self.docker_bridge_ip))

allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -p udp -s {} -d {} -j ACCEPT".format\
(docker_mgmt_ip, self.docker_bridge_ip))
allow_internal_docker_ip_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -A INPUT -p udp -s {} -d {} -j ACCEPT".format
(docker_mgmt_ip, self.docker_bridge_ip))
return allow_internal_docker_ip_cmds

def is_rule_ipv4(self, rule_props):
if (("SRC_IP" in rule_props and rule_props["SRC_IP"]) or
("DST_IP" in rule_props and rule_props["DST_IP"])):
("DST_IP" in rule_props and rule_props["DST_IP"])):
return True
else:
return False

def is_rule_ipv6(self, rule_props):
if (("SRC_IPV6" in rule_props and rule_props["SRC_IPV6"]) or
("DST_IPV6" in rule_props and rule_props["DST_IPV6"])):
("DST_IPV6" in rule_props and rule_props["DST_IPV6"])):
return True
else:
return False
Expand All @@ -235,10 +235,8 @@ class ControlPlaneAclManager(object):
Retrieves current ACL tables and rules from Config DB, translates
control plane ACLs into a list of iptables commands that can be run
in order to install ACL rules.

Returns:
A list of strings, each string is an iptables shell command

"""
iptables_cmds = []

Expand Down Expand Up @@ -310,7 +308,6 @@ class ControlPlaneAclManager(object):
iptables_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -p tcp --dport 179 -j ACCEPT")
iptables_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -A INPUT -p tcp --sport 179 -j ACCEPT")


# Get current ACL tables and rules from Config DB
self._tables_db_info = self.config_db_map[namespace].get_table(self.ACL_TABLE)
self._rules_db_info = self.config_db_map[namespace].get_table(self.ACL_RULE)
Expand All @@ -331,11 +328,11 @@ class ControlPlaneAclManager(object):
for acl_service in acl_services:
if acl_service not in self.ACL_SERVICES:
log_warning("Ignoring control plane ACL '{}' with unrecognized service '{}'"
.format(table_name, acl_service))
.format(table_name, acl_service))
continue

log_info("Translating ACL rules for control plane ACL '{}' (service: '{}')"
.format(table_name, acl_service))
.format(table_name, acl_service))

# Obtain default IP protocol(s) and destination port(s) for this service
ip_protocols = self.ACL_SERVICES[acl_service]["ip_protocols"]
Expand Down Expand Up @@ -366,18 +363,18 @@ class ControlPlaneAclManager(object):

if (self.is_rule_ipv6(rule_props) and (table_ip_version == 4)):
log_error("CtrlPlane ACL table {} is a IPv4 based table and rule {} is a IPV6 rule! Ignoring rule."
.format(table_name, rule_id))
.format(table_name, rule_id))
acl_rules.pop(rule_props["PRIORITY"])
elif (self.is_rule_ipv4(rule_props) and (table_ip_version == 6)):
log_error("CtrlPlane ACL table {} is a IPv6 based table and rule {} is a IPV4 rule! Ignroing rule."
.format(table_name, rule_id))
.format(table_name, rule_id))
acl_rules.pop(rule_props["PRIORITY"])

# If we were unable to determine whether this ACL table contains
# IPv4 or IPv6 rules, log a message and skip processing this table.
if not table_ip_version:
log_warning("Unable to determine if ACL table '{}' contains IPv4 or IPv6 rules. Skipping table..."
.format(table_name))
.format(table_name))
continue

# For each ACL rule in this table (in descending order of priority)
Expand Down Expand Up @@ -409,7 +406,7 @@ class ControlPlaneAclManager(object):
tcp_flags_mask = int(tcp_flags_mask, 16)

if tcp_flags_mask > 0:
rule_cmd += " --tcp-flags {mask} {flags}".format(mask = self.parse_int_to_tcp_flags(tcp_flags_mask), flags = self.parse_int_to_tcp_flags(tcp_flags))
rule_cmd += " --tcp-flags {mask} {flags}".format(mask=self.parse_int_to_tcp_flags(tcp_flags_mask), flags=self.parse_int_to_tcp_flags(tcp_flags))

# Append the packet action as the jump target
rule_cmd += " -j {}".format(rule_props["PACKET_ACTION"])
Expand Down Expand Up @@ -472,7 +469,7 @@ class ControlPlaneAclManager(object):
config_db_subscriber_table_map[namespace] = []
config_db_subscriber_table_map[namespace].append(subscribe_acl_table)
config_db_subscriber_table_map[namespace].append(subscribe_acl_rule_table)
#Loop on select to see if any event happen on config db of any namespace
# Loop on select to see if any event happen on config db of any namespace
jleveque marked this conversation as resolved.
Show resolved Hide resolved
while True:
(state, c) = sel.select(SELECT_TIMEOUT_MS)
# Continue if select is timeout or selectable object is not return
Expand All @@ -488,6 +485,7 @@ class ControlPlaneAclManager(object):

# ============================= Functions =============================


def main():
log_info("Starting up...")

Expand All @@ -503,3 +501,4 @@ def main():

if __name__ == "__main__":
main()

abdosi marked this conversation as resolved.
Show resolved Hide resolved