[Multi-Asic] Forward SNMP requests received on front panel interface to SNMP agent in host. (#5420)
* [Multi-Asic] Forward SNMP requests destined to loopback IP, and coming in through the front panel interface present in the network namespace, to SNMP agent running in the linux host. * Updates based on comments * Further updates in docker_image_ctl.j2 and caclmgrd * Change the variable for net config file. * Updated the comments in the code. * No need to clean up the exising NAT rules if present, which could be created by some other process. * Delete our rule first and add it back, to take care of caclmgrd restart. Another benefit is that we delete only our rules, rather than earlier approach of "iptables -F" which cleans up all rules. * Keeping the original logic to clean the NAT entries, to revist when NAT feature added in namespace. * Missing updates to log_info call.
This commit is contained in:
parent
b70c6f72b2
commit
cff716f7a5
@ -91,6 +91,10 @@ function postStartAction()
|
|||||||
{
|
{
|
||||||
{%- if docker_container_name == "database" %}
|
{%- if docker_container_name == "database" %}
|
||||||
if [ "$DEV" ]; then
|
if [ "$DEV" ]; then
|
||||||
|
# Enable the forwarding on eth0 interface in namespace.
|
||||||
|
SYSCTL_NET_CONFIG="/etc/sysctl.d/sysctl-net.conf"
|
||||||
|
docker exec -i database$DEV sed -i -e "s/^net.ipv4.conf.eth0.forwarding=0/net.ipv4.conf.eth0.forwarding=1/;
|
||||||
|
s/^net.ipv6.conf.eth0.forwarding=0/net.ipv6.conf.eth0.forwarding=1/" $SYSCTL_NET_CONFIG
|
||||||
docker exec -i database$DEV sysctl --system -e
|
docker exec -i database$DEV sysctl --system -e
|
||||||
link_namespace $DEV
|
link_namespace $DEV
|
||||||
fi
|
fi
|
||||||
|
@ -81,7 +81,9 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
|
|||||||
self.config_db_map[''].connect()
|
self.config_db_map[''].connect()
|
||||||
self.iptables_cmd_ns_prefix[''] = ""
|
self.iptables_cmd_ns_prefix[''] = ""
|
||||||
self.namespace_mgmt_ip = self.get_namespace_mgmt_ip(self.iptables_cmd_ns_prefix[''], '')
|
self.namespace_mgmt_ip = self.get_namespace_mgmt_ip(self.iptables_cmd_ns_prefix[''], '')
|
||||||
|
self.namespace_mgmt_ipv6 = self.get_namespace_mgmt_ipv6(self.iptables_cmd_ns_prefix[''], '')
|
||||||
self.namespace_docker_mgmt_ip = {}
|
self.namespace_docker_mgmt_ip = {}
|
||||||
|
self.namespace_docker_mgmt_ipv6 = {}
|
||||||
namespaces = device_info.get_all_namespaces()
|
namespaces = device_info.get_all_namespaces()
|
||||||
for front_asic_namespace in namespaces['front_ns']:
|
for front_asic_namespace in namespaces['front_ns']:
|
||||||
self.config_db_map[front_asic_namespace] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespace)
|
self.config_db_map[front_asic_namespace] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespace)
|
||||||
@ -89,11 +91,15 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
|
|||||||
self.iptables_cmd_ns_prefix[front_asic_namespace] = "ip netns exec " + front_asic_namespace + " "
|
self.iptables_cmd_ns_prefix[front_asic_namespace] = "ip netns exec " + front_asic_namespace + " "
|
||||||
self.namespace_docker_mgmt_ip[front_asic_namespace] = self.get_namespace_mgmt_ip(self.iptables_cmd_ns_prefix[front_asic_namespace],
|
self.namespace_docker_mgmt_ip[front_asic_namespace] = self.get_namespace_mgmt_ip(self.iptables_cmd_ns_prefix[front_asic_namespace],
|
||||||
front_asic_namespace)
|
front_asic_namespace)
|
||||||
|
self.namespace_docker_mgmt_ipv6[front_asic_namespace] = self.get_namespace_mgmt_ipv6(self.iptables_cmd_ns_prefix[front_asic_namespace],
|
||||||
|
front_asic_namespace)
|
||||||
|
|
||||||
for back_asic_namespace in namespaces['back_ns']:
|
for back_asic_namespace in namespaces['back_ns']:
|
||||||
self.iptables_cmd_ns_prefix[back_asic_namespace] = "ip netns exec " + back_asic_namespace + " "
|
self.iptables_cmd_ns_prefix[back_asic_namespace] = "ip netns exec " + back_asic_namespace + " "
|
||||||
self.namespace_docker_mgmt_ip[back_asic_namespace] = self.get_namespace_mgmt_ip(self.iptables_cmd_ns_prefix[back_asic_namespace],
|
self.namespace_docker_mgmt_ip[back_asic_namespace] = self.get_namespace_mgmt_ip(self.iptables_cmd_ns_prefix[back_asic_namespace],
|
||||||
back_asic_namespace)
|
back_asic_namespace)
|
||||||
|
self.namespace_docker_mgmt_ipv6[back_asic_namespace] = self.get_namespace_mgmt_ipv6(self.iptables_cmd_ns_prefix[back_asic_namespace],
|
||||||
|
back_asic_namespace)
|
||||||
|
|
||||||
def get_namespace_mgmt_ip(self, iptable_ns_cmd_prefix, namespace):
|
def get_namespace_mgmt_ip(self, iptable_ns_cmd_prefix, namespace):
|
||||||
ip_address_get_command = iptable_ns_cmd_prefix + "ip -4 -o addr show " + ("eth0" if namespace else "docker0") +\
|
ip_address_get_command = iptable_ns_cmd_prefix + "ip -4 -o addr show " + ("eth0" if namespace else "docker0") +\
|
||||||
@ -101,6 +107,11 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
|
|||||||
|
|
||||||
return self.run_commands([ip_address_get_command])
|
return self.run_commands([ip_address_get_command])
|
||||||
|
|
||||||
|
def get_namespace_mgmt_ipv6(self, iptable_ns_cmd_prefix, namespace):
|
||||||
|
ipv6_address_get_command = iptable_ns_cmd_prefix + "ip -6 -o addr show scope global " + ("eth0" if namespace else "docker0") +\
|
||||||
|
" | awk '{print $4}' | cut -d'/' -f1 | head -1"
|
||||||
|
return self.run_commands([ipv6_address_get_command])
|
||||||
|
|
||||||
def run_commands(self, commands):
|
def run_commands(self, commands):
|
||||||
"""
|
"""
|
||||||
Given a list of shell commands, run them in order
|
Given a list of shell commands, run them in order
|
||||||
@ -202,6 +213,39 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
|
|||||||
(docker_mgmt_ip, self.namespace_mgmt_ip))
|
(docker_mgmt_ip, self.namespace_mgmt_ip))
|
||||||
return allow_internal_docker_ip_cmds
|
return allow_internal_docker_ip_cmds
|
||||||
|
|
||||||
|
def generate_fwd_snmp_traffic_from_namespace_to_host_commands(self, namespace):
|
||||||
|
"""
|
||||||
|
The below SNAT and DNAT rules are added in asic namespace in multi-ASIC platforms. It helps to forward the SNMP request coming
|
||||||
|
in through the front panel interfaces created/present in the asic namespace to the SNMP Agent running in SNMP container in
|
||||||
|
linux host network namespace. The external IP addresses are NATed to the internal docker IP addresses for the SNMP Agent to respond.
|
||||||
|
"""
|
||||||
|
fwd_snmp_traffic_from_namespace_to_host_cmds = []
|
||||||
|
|
||||||
|
if namespace:
|
||||||
|
# IPv4 rules
|
||||||
|
fwd_snmp_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -t nat -X")
|
||||||
|
fwd_snmp_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "iptables -t nat -F")
|
||||||
|
|
||||||
|
fwd_snmp_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] +
|
||||||
|
"iptables -t nat -A PREROUTING -p udp --dport {} -j DNAT --to-destination {}".format
|
||||||
|
(self.ACL_SERVICES['SNMP']['dst_ports'][0], self.namespace_mgmt_ip))
|
||||||
|
fwd_snmp_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] +
|
||||||
|
"iptables -t nat -A POSTROUTING -p udp --dport {} -j SNAT --to-source {}".format
|
||||||
|
(self.ACL_SERVICES['SNMP']['dst_ports'][0], self.namespace_docker_mgmt_ip[namespace]))
|
||||||
|
|
||||||
|
# IPv6 rules
|
||||||
|
fwd_snmp_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -t nat -X")
|
||||||
|
fwd_snmp_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] + "ip6tables -t nat -F")
|
||||||
|
|
||||||
|
fwd_snmp_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] +
|
||||||
|
"ip6tables -t nat -A PREROUTING -p udp --dport {} -j DNAT --to-destination {}".format
|
||||||
|
(self.ACL_SERVICES['SNMP']['dst_ports'][0], self.namespace_mgmt_ipv6))
|
||||||
|
fwd_snmp_traffic_from_namespace_to_host_cmds.append(self.iptables_cmd_ns_prefix[namespace] +
|
||||||
|
"ip6tables -t nat -A POSTROUTING -p udp --dport {} -j SNAT --to-source {}".format
|
||||||
|
(self.ACL_SERVICES['SNMP']['dst_ports'][0], self.namespace_docker_mgmt_ipv6[namespace]))
|
||||||
|
|
||||||
|
return fwd_snmp_traffic_from_namespace_to_host_cmds
|
||||||
|
|
||||||
def is_rule_ipv4(self, rule_props):
|
def is_rule_ipv4(self, rule_props):
|
||||||
if (("SRC_IP" in rule_props and rule_props["SRC_IP"]) or
|
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"])):
|
||||||
@ -429,6 +473,19 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
|
|||||||
|
|
||||||
self.run_commands(iptables_cmds)
|
self.run_commands(iptables_cmds)
|
||||||
|
|
||||||
|
def update_control_plane_nat_acls(self, namespace):
|
||||||
|
"""
|
||||||
|
Convenience wrapper which programs the NAT rules for allowing the
|
||||||
|
snmp traffic coming on the front panel interface
|
||||||
|
"""
|
||||||
|
# Add iptables commands to allow front panel snmp traffic
|
||||||
|
iptables_cmds = self.generate_fwd_snmp_traffic_from_namespace_to_host_commands(namespace)
|
||||||
|
self.log_info("Issuing the following iptables commands:")
|
||||||
|
for cmd in iptables_cmds:
|
||||||
|
self.log_info(" " + cmd)
|
||||||
|
|
||||||
|
self.run_commands(iptables_cmds)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# Select Time-out for 10 Seconds
|
# Select Time-out for 10 Seconds
|
||||||
SELECT_TIMEOUT_MS = 1000 * 10
|
SELECT_TIMEOUT_MS = 1000 * 10
|
||||||
@ -453,6 +510,7 @@ class ControlPlaneAclManager(daemon_base.DaemonBase):
|
|||||||
for namespace in self.config_db_map.keys():
|
for namespace in self.config_db_map.keys():
|
||||||
# Unconditionally update control plane ACLs once at start on given namespace
|
# Unconditionally update control plane ACLs once at start on given namespace
|
||||||
self.update_control_plane_acls(namespace)
|
self.update_control_plane_acls(namespace)
|
||||||
|
self.update_control_plane_nat_acls(namespace)
|
||||||
# Connect to Config DB of given namespace
|
# Connect to Config DB of given namespace
|
||||||
acl_db_connector = swsscommon.DBConnector("CONFIG_DB", 0, False, namespace)
|
acl_db_connector = swsscommon.DBConnector("CONFIG_DB", 0, False, namespace)
|
||||||
# Subscribe to notifications when ACL tables changes
|
# Subscribe to notifications when ACL tables changes
|
||||||
|
Loading…
Reference in New Issue
Block a user