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

mgmt_vrf_namespace2: Repeating management vrf using namespace solutio… #2431

Closed
wants to merge 1 commit into from
Closed
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
12 changes: 12 additions & 0 deletions dockers/docker-snmp-sv2/snmpd.conf.j2
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,23 @@ load 12 10 5
# Note: disabled snmp traps due to side effect of causing snmpd to listen on all ports (0.0.0.0)
#
# send SNMPv1 traps
{%if v1_trap_dest != 'default' %}
trapsink {{ v1_trap_dest }} public
{% else %}
#trapsink localhost public
{% endif %}
# send SNMPv2c traps
{%if v2_trap_dest != 'default' %}
trap2sink {{ v2_trap_dest }} public
{% else %}
#trap2sink localhost public
{% endif %}
# send SNMPv2c INFORMs
{%if v3_trap_dest != 'default' %}
informsink {{ v3_trap_dest }} public
{% else %}
#informsink localhost public
{% endif %}

# Note that you typically only want *one* of these three lines
# Uncommenting two (or all three) will result in multiple copies of each notification.
Expand Down
56 changes: 56 additions & 0 deletions files/build_templates/docker_image_ctl.j2
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,62 @@ function preStartAction()
echo -n > /tmp/dump.rdb
docker cp /tmp/dump.rdb database:/var/lib/redis/
fi
{%- elif docker_container_name == "snmp" %}
localhost="localhost"
snmpUdpPort=162
vrfenabled=`/usr/bin/redis-cli -n 4 hget "MGMT_VRF_CONFIG|vrf_global" mgmtVrfEnabled`
v1SnmpTrapIp=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" DestIp`
v1SnmpTrapPort=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" DestPort`
v1MgmtVrf=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" vrf`
v2SnmpTrapIp=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" DestIp`
v2SnmpTrapPort=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" DestPort`
v2MgmtVrf=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" vrf`
v3SnmpTrapIp=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" DestIp`
v3SnmpTrapPort=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" DestPort`
v3MgmtVrf=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" vrf`

if [ "$v1MgmtVrf" == "mgmt" ]
then
ip netns exec mgmt iptables -t nat -D PREROUTING -i if1 -p udp -d 127.100.100.1 --dport 62101 -j DNAT --to-destination $v1SnmpTrapIp:$v1SnmpTrapPort
ip netns exec mgmt iptables -t nat -A PREROUTING -i if1 -p udp -d 127.100.100.1 --dport 62101 -j DNAT --to-destination $v1SnmpTrapIp:$v1SnmpTrapPort
sed -i 's/v1_trap_dest:.*/v1_trap_dest: 127.100.100.1:62101/' "/etc/sonic/snmp.yml"
elif [ "${v1SnmpTrapIp}" != "" ] && [ "${v1SnmpTrapIp}" != "${localhost}" ] && [ "${v1SnmpTrapIp}" != "default" ]
then
sed -i "s/v1_trap_dest:.*/v1_trap_dest: ${v1SnmpTrapIp}:${v1SnmpTrapPort}/" "/etc/sonic/snmp.yml"
elif [ "${v1SnmpTrapIp}" == "${localhost}" ]
then
sed -i "s/v1_trap_dest:.*/v1_trap_dest: ${localhost}:${snmpUdpPort}/" "/etc/sonic/snmp.yml"
else
sed -i "s/v1_trap_dest:.*/v1_trap_dest: default/" "etc/sonic/snmp.yml"
fi
if [ "$v2MgmtVrf" == "mgmt" ]
then
ip netns exec mgmt iptables -t nat -D PREROUTING -i if1 -p udp -d 127.100.100.1 --dport 62102 -j DNAT --to-destination $v2SnmpTrapIp:$v2SnmpTrapPort
ip netns exec mgmt iptables -t nat -A PREROUTING -i if1 -p udp -d 127.100.100.1 --dport 62102 -j DNAT --to-destination $v2SnmpTrapIp:$v2SnmpTrapPort
sed -i 's/v2_trap_dest:.*/v2_trap_dest: 127.100.100.1:62102/' "/etc/sonic/snmp.yml"
elif [ "${v2SnmpTrapIp}" != "" ] && [ "${v2SnmpTrapIp}" != "${localhost}" ] && [ "${v2SnmpTrapIp}" != "default" ]
then
sed -i "s/v2_trap_dest:.*/v2_trap_dest: ${v2SnmpTrapIp}:${v2SnmpTrapPort}/" "/etc/sonic/snmp.yml"
elif [ "${v2SnmpTrapIp}" == "${localhost}" ]
then
sed -i "s/v2_trap_dest:.*/v2_trap_dest: ${localhost}:${snmpUdpPort}/" "/etc/sonic/snmp.yml"
else
sed -i "s/v2_trap_dest:.*/v2_trap_dest: default/" "etc/sonic/snmp.yml"
fi
if [ "$v3MgmtVrf" == "mgmt" ]
then
ip netns exec mgmt iptables -t nat -D PREROUTING -i if1 -p udp -d 127.100.100.1 --dport 62103 -j DNAT --to-destination $v3SnmpTrapIp:$v3SnmpTrapPort
ip netns exec mgmt iptables -t nat -A PREROUTING -i if1 -p udp -d 127.100.100.1 --dport 62103 -j DNAT --to-destination $v3SnmpTrapIp:$v3SnmpTrapPort
sed -i 's/v3_trap_dest:.*/v3_trap_dest: 127.100.100.1:62103/' "/etc/sonic/snmp.yml"
elif [ "${v3SnmpTrapIp}" != "" ] && [ "${v3SnmpTrapIp}" != "${localhost}" ] && [ "${v3SnmpTrapIp}" != "default" ]
then
sed -i "s/v3_trap_dest:.*/v3_trap_dest: ${v3SnmpTrapIp}:${v3SnmpTrapPort}/" "/etc/sonic/snmp.yml"
elif [ "${v3SnmpTrapIp}" == "${localhost}" ]
then
sed -i "s/v3_trap_dest:.*/v3_trap_dest: ${localhost}:${snmpUdpPort}/" "etc/sonic/snmp.yml"
else
sed -i "s/v3_trap_dest:.*/v3_trap_dest: default/" "etc/sonic/snmp.yml"
fi
{%- else %}
: # nothing
{%- endif %}
Expand Down
12 changes: 12 additions & 0 deletions files/build_templates/sonic_debian_extension.j2
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,18 @@ sudo LANG=C chroot $FILESYSTEM_ROOT systemctl enable hostcfgd.service
sudo cp $IMAGE_CONFIGS/hostcfgd/hostcfgd $FILESYSTEM_ROOT/usr/bin/
sudo cp $IMAGE_CONFIGS/hostcfgd/*.j2 $FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES/

# Copy the management VRF related scripts
sudo cp $IMAGE_CONFIGS/interfaces/if_pre_up_netns $FILESYSTEM_ROOT/usr/bin/
sudo cp $IMAGE_CONFIGS/interfaces/if_up_netns $FILESYSTEM_ROOT/usr/bin/
sudo cp $IMAGE_CONFIGS/interfaces/if_down_netns $FILESYSTEM_ROOT/usr/bin/
sudo cp $IMAGE_CONFIGS/interfaces/create-mgmt-vrf-iptables.sh $FILESYSTEM_ROOT/usr/bin/
sudo cp $IMAGE_CONFIGS/interfaces/delete-mgmt-vrf-iptables.sh $FILESYSTEM_ROOT/usr/bin/

# Copy vrfcfgd files
sudo cp $IMAGE_CONFIGS/vrfcfgd/vrfcfgd.service $FILESYSTEM_ROOT/etc/systemd/system/
sudo LANG=C chroot $FILESYSTEM_ROOT systemctl enable vrfcfgd.service
sudo cp $IMAGE_CONFIGS/vrfcfgd/vrfcfgd $FILESYSTEM_ROOT/usr/bin/

# Copy the buffer configuration template
sudo cp $BUILD_TEMPLATES/buffers_config.j2 $FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES/

Expand Down
77 changes: 76 additions & 1 deletion files/image_config/hostcfgd/hostcfgd
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ TACPLUS_SERVER_PASSKEY_DEFAULT = ""
TACPLUS_SERVER_TIMEOUT_DEFAULT = "5"
TACPLUS_SERVER_AUTH_TYPE_DEFAULT = "pap"

MAX_TACPLUS_SERVERS=10
TACPLUS_SERVER_LOCAL_IP="127.100.100.1"
TACPLUS_LOCAL_PORT_START=62000


def is_true(val):
if val == 'True' or val == 'true':
Expand Down Expand Up @@ -55,7 +59,30 @@ class AaaCfg(object):
self.auth = {}
self.tacplus_global = {}
self.tacplus_servers = {}
# Maintain the mapping between user configured tacacs server publicIP to localport
self.localport_for_server_publicip = {}
# Maintain the mapping between user configured tacacs server publicPort for the serverIP
self.publicport_for_server_publicip = {}
# Maintain the local_port_status for all 10 servers as either "free" or "used"
self.local_port_status = {}
self.debug = False
# next_free_local_port shows the next least numbered free port between 62000 and 62009
#Initializing next_free_PORT as 62000
self.next_free_local_port = TACPLUS_LOCAL_PORT_START
for x in range (MAX_TACPLUS_SERVERS):
#Initializing all the available 10 ports as "free"
self.local_port_status[x]="free"


def update_next_free_local_port(self):
# Check all the status of 10 ports and find the next available free port
for x in range (MAX_TACPLUS_SERVERS):
local_port = TACPLUS_LOCAL_PORT_START + x
if self.local_port_status[x]=='free':
#Chaning the next free port to this free local port
self.next_free_local_port = local_port
break


# Load conf from ConfigDb
def load(self, aaa_conf, tac_global_conf, tacplus_conf):
Expand Down Expand Up @@ -86,8 +113,47 @@ class AaaCfg(object):
def tacacs_server_update(self, key, data, modify_conf=True):
if data == {}:
if key in self.tacplus_servers:
#Deleting tacplus_server
if (self.tacplus_servers[key]['vrf'] == "mgmt"):
#Tacacs Server in Management VRF has to be deleted
local_port_used = self.localport_for_server_publicip[key]
user_configured_port = self.publicport_for_server_publicip[key]
# Compose the ip netns command to remove the previously created DNAT rule from management VRF iptables.
cmd2 = "ip netns exec mgmt iptables -t nat -D PREROUTING -i if1 -p tcp -d {0} --dport {1} -j DNAT --to-destination {2}:{3}".format(TACPLUS_SERVER_LOCAL_IP, local_port_used, key, user_configured_port)
os.system(cmd2)
# Marking local_port as free
self.local_port_status[local_port_used-TACPLUS_LOCAL_PORT_START] = "free"
# If the self.next_free_local_port is greater than the currently freed port, update it with this least port number
if (self.next_free_local_port > local_port_used):
#Changing next free from old value to new value
self.next_free_local_port = self.localport_for_server_publicip[key]

# Irrespectie of server in management VRF or default VRF, delete it from our tacplus_server list.
del self.tacplus_servers[key]

else:
if (data['vrf'] == "mgmt") :
# tacplus_server need to be added in management VRF.
# Save the user configured publicPort that is required later while adding DNAT rule.
data['user_configured_server_port'] = data['tcp_port']
# set the tcp_port in data to the local port to be used in the tacacs config file.
data['tcp_port'] = str(self.next_free_local_port)

# Compose the iptables rule to be added to in management namespace.
cmd = "ip netns exec mgmt iptables -t nat -A PREROUTING -i if1 -p tcp -d {0} --dport {1} -j DNAT --to-destination {2}:{3}".format(TACPLUS_SERVER_LOCAL_IP, self.next_free_local_port, key, data['user_configured_server_port'])
os.system(cmd)

#Update the mapping table with the local port that is used and the actual publicIP configured by user.
# mapping table is index using the tacplus server publicIP (which is the "key").
self.localport_for_server_publicip[key] = self.next_free_local_port
self.publicport_for_server_publicip[key] = data['user_configured_server_port']

# Mark the local_port array element as "used"
self.local_port_status[self.next_free_local_port-TACPLUS_LOCAL_PORT_START]="used"
# Call the function to update the next available free port.
self.update_next_free_local_port()

# Update internal data structure tacplus_servers with the data.
self.tacplus_servers[key] = data

if modify_conf:
Expand All @@ -103,7 +169,16 @@ class AaaCfg(object):
if self.tacplus_servers:
for addr in self.tacplus_servers:
server = tacplus_global.copy()
server['ip'] = addr
# It is expected that user configured ports are less than 62000. Value about 62000 until 62009 are local ports
# used for NAT that is requried for supporting management VRF.
# If localport has been assigned as part of NAT, use that local IP & local port instead of publicIP and publicPort.
# This will update the tacplus server configuration file with local IP and local port if the server is reachable via the management VRF.
if (int(self.tacplus_servers[addr]['tcp_port']) >= TACPLUS_LOCAL_PORT_START):
if (int(self.tacplus_servers[addr]['tcp_port']) < TACPLUS_LOCAL_PORT_START+MAX_TACPLUS_SERVERS):
# This means that the publicIP is already mapped to local IP and local port
server['ip'] = TACPLUS_SERVER_LOCAL_IP
else :
server['ip'] = addr
server.update(self.tacplus_servers[addr])
servers_conf.append(server)
sorted(servers_conf, key=lambda t: t['priority'], reverse=True)
Expand Down
27 changes: 27 additions & 0 deletions files/image_config/interfaces/create-mgmt-vrf-iptables.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin//bash

set -e

VRFNAME="mgmt"

ip netns exec $VRFNAME iptables -t nat -A PREROUTING -i eth0 -j $IF_MGMT_VRF_CHAIN

ip netns exec $VRFNAME iptables -t nat -A POSTROUTING -p tcp -o $IF_PEER_IFACE -j SNAT --to-source $IF_IF1_IP:62000-65000
ip netns exec $VRFNAME iptables -t nat -A POSTROUTING -p udp -o $IF_PEER_IFACE -j SNAT --to-source $IF_IF1_IP:62000-65000

ip netns exec $VRFNAME iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

ip netns exec $VRFNAME iptables -t nat -A $IF_MGMT_VRF_CHAIN -p tcp --dport 22 -j DNAT --to-destination $IF_IF2_IP

ip netns exec $VRFNAME iptables -t nat -A $IF_MGMT_VRF_CHAIN -p tcp --dport 20 -j DNAT --to-destination $IF_IF2_IP

ip netns exec $VRFNAME iptables -t nat -A $IF_MGMT_VRF_CHAIN -p tcp --dport 21 -j DNAT --to-destination $IF_IF2_IP

ip netns exec $VRFNAME iptables -t nat -A $IF_MGMT_VRF_CHAIN -p udp --dport 161 -j DNAT --to-destination $IF_IF2_IP

ip netns exec $VRFNAME iptables -t nat -A $IF_MGMT_VRF_CHAIN -p udp --dport 69 -j DNAT --to-destination ${IF_IF2_IP}

ip netns exec $VRFNAME iptables -t nat -A $IF_MGMT_VRF_CHAIN -p tcp --dport 80 -j DNAT --to-destination $IF_IF2_IP

ip netns exec $VRFNAME iptables -t nat -A $IF_MGMT_VRF_CHAIN -p tcp --dport 443 -j DNAT --to-destination $IF_IF2_IP

32 changes: 32 additions & 0 deletions files/image_config/interfaces/delete-mgmt-vrf-iptables.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin//bash

set -e

VRFNAME="mgmt"

ip netns exec $VRFNAME iptables -t nat -D PREROUTING -i eth0 -j $IF_MGMT_VRF_CHAIN

ip netns exec $VRFNAME iptables -t nat -D POSTROUTING -p tcp -o ${IF_PEER_IFACE} -j SNAT --to-source ${IF_IF1_IP}:62000-65000
ip netns exec $VRFNAME iptables -t nat -D POSTROUTING -p udp -o ${IF_PEER_IFACE} -j SNAT --to-source ${IF_IF1_IP}:62000-65000

ip netns exec $VRFNAME iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

ip netns exec $VRFNAME iptables -t nat -D $IF_MGMT_VRF_CHAIN -p tcp --dport 22 -j DNAT --to-destination ${IF_IF2_IP}

ip netns exec $VRFNAME iptables -t nat -D $IF_MGMT_VRF_CHAIN -p tcp --dport 20 -j DNAT --to-destination ${IF_IF2_IP}

ip netns exec $VRFNAME iptables -t nat -D $IF_MGMT_VRF_CHAIN -p tcp --dport 21 -j DNAT --to-destination ${IF_IF2_IP}

ip netns exec $VRFNAME iptables -t nat -D $IF_MGMT_VRF_CHAIN -p udp --dport 161 -j DNAT --to-destination ${IF_IF2_IP}

ip netns exec $VRFNAME iptables -t nat -D $IF_MGMT_VRF_CHAIN -p udp --dport 69 -j DNAT --to-destination ${IF_IF2_IP}

ip netns exec $VRFNAME iptables -t nat -D $IF_MGMT_VRF_CHAIN -p tcp --dport 80 -j DNAT --to-destination ${IF_IF2_IP}

ip netns exec $VRFNAME iptables -t nat -D $IF_MGMT_VRF_CHAIN -p tcp --dport 443 -j DNAT --to-destination ${IF_IF2_IP}

ip netns exec $VRFNAME sysctl -w net.ipv4.conf.eth0.route_localnet=0

ip netns exec $VRFNAME sysctl -w net.ipv4.conf.${IF_PEER_IFACE}.route_localnet=0

sysctl -w net.ipv4.conf.${IFACE}.route_localnet=0
28 changes: 28 additions & 0 deletions files/image_config/interfaces/if_down_netns
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/bin/sh

set -e

if [ -n "${IF_PEER_NETNS}" -a -n "${IF_PEER_IFACE}" ]
then
if OUTPUT=$(ip netns list | grep -w ${IF_PEER_NETNS})
then
# Take down the remote end of the veth
ip netns exec ${IF_PEER_NETNS} ip link set ${IF_PEER_IFACE} down

case "${IF_CONFIGURE_INTERFACES}" in
true|yes|on)
# Ifdown the interfaces inside the netns and inside
# a mount namespace with /run/network.nsname mounted
# on /run/network
unshare -m /bin/sh <<-EOF
mount --make-rprivate /
mount --bind /run/network.${IF_PEER_NETNS} /run/network
/usr/bin/delete-mgmt-vrf-iptables.sh

logger "if_down_netns: Doing ifdown for the interfaces present in management namespace."
ip netns exec ${IF_PEER_NETNS} ifdown -i /etc/network/interfaces.${IF_PEER_NETNS} -a
EOF
;;
esac
fi
fi
54 changes: 54 additions & 0 deletions files/image_config/interfaces/if_pre_up_netns
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/bin/sh
# filename:

set -e

if [ -n "${IF_PEER_NETNS}" -a -n "${IF_PEER_IFACE}" ]
then
logger "if_pre_up_netns: User is enabling management VRF. interfaces.j2 has set the required variables. Create the management namespace if not already present."
# Create netns if it doesn't already exist, and bring up the loopback
if ! OUTPUT=$(ip netns list | grep -w ${IF_PEER_NETNS})
then
logger "if_pre_up_netns: management vrf does not exist. Create it now."
mkdir -p /run/network.${IF_PEER_NETNS}
rm -rf /run/network.${IF_PEER_NETNS}/*
ip netns add ${IF_PEER_NETNS}
ip netns exec ${IF_PEER_NETNS} ip link set lo up
else
logger "if_pre_up_netns: management vrf already exists. No need to create it."
fi

if OUTPUT=$(ifconfig eth0)
then
logger "if_pre_up_netns: eth0 is in default VRF. Move it to management VRF"
# Move the management interface eth0 from default namespace to management namespace
ip link set dev eth0 netns ${IF_PEER_NETNS}
else
logger "if_pre_up_netns: eth0 is NOT in default VRF. No need to move it."
fi

# if veth pair is already existing, there will be a link by name if1@if2
if ! OUTPUT=$(ethtool -S if2)
then
logger "if_pre_up_netns: if1 & if2 are NOT in eth pair. Connect them via eth pair now"
# Add the veth pair for if2 with peer as if1
ip link add name ${IFACE} type veth peer name ${IF_PEER_IFACE}
else
logger "if_pre_up_netns: if1 & if2 are already in eth pair. NO need to connect them via eth pair now"
fi

# if if1 is already part of management namespace, nothing to do. Else move it to the management namespace
if ! OUTPUT=$(ip netns exec ${IF_PEER_NETNS} ifconfig if1)
then
logger "if_pre_up_netns: if1 is not in management VRF. Move it now"
# Put the remote end interface if1 into the netns
ip link set dev ${IF_PEER_IFACE} netns ${IF_PEER_NETNS}
else
logger "if_pre_up_netns: if1 is alerady in management VRF. no need to move it"
fi

# Set if2 as UP
logger "if_pre_up_netns: Bringing up the if2"
ip link set ${IFACE} up

fi
Loading