[swss]: Reduce tunnel_packet_handler memory usage (#9762)
* Configure scapy to not store sniffed packets Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
This commit is contained in:
parent
62ad4bf3bb
commit
59a7dc9f1e
@ -9,15 +9,17 @@ destination IP to trigger the process of obtaining neighbor information
|
|||||||
"""
|
"""
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from ipaddress import ip_interface
|
from ipaddress import ip_interface
|
||||||
|
|
||||||
|
from swsssdk import ConfigDBConnector, SonicV2Connector
|
||||||
|
from sonic_py_common import logger as log
|
||||||
|
|
||||||
from pyroute2 import IPRoute
|
from pyroute2 import IPRoute
|
||||||
from scapy.layers.inet import IP
|
from scapy.layers.inet import IP
|
||||||
from scapy.layers.inet6 import IPv6
|
from scapy.layers.inet6 import IPv6
|
||||||
from scapy.sendrecv import AsyncSniffer
|
from scapy.sendrecv import AsyncSniffer
|
||||||
from swsssdk import ConfigDBConnector, SonicV2Connector
|
|
||||||
from sonic_py_common import logger as log
|
|
||||||
|
|
||||||
logger = log.Logger()
|
logger = log.Logger()
|
||||||
|
|
||||||
@ -36,6 +38,10 @@ RTM_NEWLINK = 'RTM_NEWLINK'
|
|||||||
|
|
||||||
|
|
||||||
class TunnelPacketHandler(object):
|
class TunnelPacketHandler(object):
|
||||||
|
"""
|
||||||
|
This class handles unroutable tunnel packets that are trapped
|
||||||
|
to the CPU from the ASIC.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.config_db = ConfigDBConnector()
|
self.config_db = ConfigDBConnector()
|
||||||
@ -68,19 +74,32 @@ class TunnelPacketHandler(object):
|
|||||||
|
|
||||||
return self._portchannel_intfs
|
return self._portchannel_intfs
|
||||||
|
|
||||||
def get_portchannel_index_mapping(self):
|
def get_intf_name(self, msg):
|
||||||
"""
|
"""
|
||||||
Gets a mapping of interface kernel indices to portchannel interfaces
|
Gets the interface name for a netlink msg
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(str) The interface name, or the empty string if no interface
|
||||||
|
name was found
|
||||||
|
"""
|
||||||
|
attr_list = msg.get('attrs', list())
|
||||||
|
|
||||||
|
for attribute, val in attr_list:
|
||||||
|
if attribute == 'IFLA_IFNAME':
|
||||||
|
return val
|
||||||
|
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def netlink_msg_is_for_portchannel(self, msg):
|
||||||
|
"""
|
||||||
|
Determines if a netlink message is about a PortChannel interface
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
(list) integers representing kernel indices
|
(list) integers representing kernel indices
|
||||||
"""
|
"""
|
||||||
index_map = {}
|
ifname = self.get_intf_name(msg)
|
||||||
for portchannel in self.portchannel_intfs:
|
|
||||||
index = self.netlink_api.link_lookup(ifname=portchannel[0])[0]
|
|
||||||
index_map[index] = portchannel
|
|
||||||
|
|
||||||
return index_map
|
return ifname in [name for name, _ in self.portchannel_intfs]
|
||||||
|
|
||||||
def get_up_portchannels(self):
|
def get_up_portchannels(self):
|
||||||
"""
|
"""
|
||||||
@ -89,15 +108,16 @@ class TunnelPacketHandler(object):
|
|||||||
Returns:
|
Returns:
|
||||||
(list) of interface names which are up, as strings
|
(list) of interface names which are up, as strings
|
||||||
"""
|
"""
|
||||||
pc_index_map = self.get_portchannel_index_mapping()
|
portchannel_intf_names = [name for name, _ in self.portchannel_intfs]
|
||||||
pc_indices = list(pc_index_map.keys())
|
link_statuses = []
|
||||||
link_statuses = self.netlink_api.get_links(*pc_indices)
|
for intf in portchannel_intf_names:
|
||||||
|
status = self.netlink_api.link("get", ifname=intf)
|
||||||
|
link_statuses.append(status[0])
|
||||||
up_portchannels = []
|
up_portchannels = []
|
||||||
|
|
||||||
for status in link_statuses:
|
for status in link_statuses:
|
||||||
if status['state'] == 'up':
|
if status['state'] == 'up':
|
||||||
port_index = status['index']
|
up_portchannels.append(self.get_intf_name(status))
|
||||||
up_portchannels.append(pc_index_map[port_index][0])
|
|
||||||
|
|
||||||
return up_portchannels
|
return up_portchannels
|
||||||
|
|
||||||
@ -117,7 +137,7 @@ class TunnelPacketHandler(object):
|
|||||||
STATE_DB,
|
STATE_DB,
|
||||||
intf_table_name,
|
intf_table_name,
|
||||||
STATE_KEY
|
STATE_KEY
|
||||||
)
|
)
|
||||||
|
|
||||||
if intf_state and intf_state.lower() != 'ok':
|
if intf_state and intf_state.lower() != 'ok':
|
||||||
return False
|
return False
|
||||||
@ -177,13 +197,13 @@ class TunnelPacketHandler(object):
|
|||||||
tunnel_type = tunnel_table[TUNNEL_TYPE_KEY].lower()
|
tunnel_type = tunnel_table[TUNNEL_TYPE_KEY].lower()
|
||||||
self_loopback_ip = tunnel_table[DST_IP_KEY]
|
self_loopback_ip = tunnel_table[DST_IP_KEY]
|
||||||
peer_loopback_ip = self.config_db.get_entry(
|
peer_loopback_ip = self.config_db.get_entry(
|
||||||
PEER_SWITCH_TABLE, peer_switch
|
PEER_SWITCH_TABLE, peer_switch
|
||||||
)[ADDRESS_IPV4_KEY]
|
)[ADDRESS_IPV4_KEY]
|
||||||
except KeyError as e:
|
except KeyError as error:
|
||||||
logger.log_warning(
|
logger.log_warning(
|
||||||
'PEER_SWITCH or TUNNEL table missing data, '
|
'PEER_SWITCH or TUNNEL table missing data, '
|
||||||
'could not find key {}'
|
'could not find key {}'
|
||||||
.format(e)
|
.format(error)
|
||||||
)
|
)
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
@ -242,12 +262,11 @@ class TunnelPacketHandler(object):
|
|||||||
come back up, we need to restart the sniffer to be able
|
come back up, we need to restart the sniffer to be able
|
||||||
to sniff traffic on the interface that has come back up.
|
to sniff traffic on the interface that has come back up.
|
||||||
"""
|
"""
|
||||||
pc_index_map = self.get_portchannel_index_mapping()
|
|
||||||
for msg in messages:
|
for msg in messages:
|
||||||
if msg['index'] in pc_index_map:
|
if self.netlink_msg_is_for_portchannel(msg):
|
||||||
if msg['state'] == 'up':
|
if msg['state'] == 'up':
|
||||||
logger.log_info('{} came back up, sniffer restart required'
|
logger.log_info('{} came back up, sniffer restart required'
|
||||||
.format(pc_index_map[msg['index']]))
|
.format(self.get_intf_name(msg)))
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -293,8 +312,8 @@ class TunnelPacketHandler(object):
|
|||||||
sniffer = AsyncSniffer(
|
sniffer = AsyncSniffer(
|
||||||
iface=sniff_intfs,
|
iface=sniff_intfs,
|
||||||
filter=packet_filter,
|
filter=packet_filter,
|
||||||
prn=_ping_inner_dst
|
prn=_ping_inner_dst,
|
||||||
|
store=0
|
||||||
)
|
)
|
||||||
sniffer.start()
|
sniffer.start()
|
||||||
while True:
|
while True:
|
||||||
@ -307,11 +326,15 @@ class TunnelPacketHandler(object):
|
|||||||
sniffer = AsyncSniffer(
|
sniffer = AsyncSniffer(
|
||||||
iface=sniff_intfs,
|
iface=sniff_intfs,
|
||||||
filter=packet_filter,
|
filter=packet_filter,
|
||||||
prn=_ping_inner_dst
|
prn=_ping_inner_dst,
|
||||||
|
store=0
|
||||||
)
|
)
|
||||||
sniffer.start()
|
sniffer.start()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
"""
|
||||||
|
Entry point for the TunnelPacketHandler class
|
||||||
|
"""
|
||||||
self.wait_for_portchannels()
|
self.wait_for_portchannels()
|
||||||
self.listen_for_tunnel_pkts()
|
self.listen_for_tunnel_pkts()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user