diff --git a/dockers/docker-sflow/Dockerfile.j2 b/dockers/docker-sflow/Dockerfile.j2 index f532a4040e07..03e209621dd9 100644 --- a/dockers/docker-sflow/Dockerfile.j2 +++ b/dockers/docker-sflow/Dockerfile.j2 @@ -12,6 +12,9 @@ RUN apt-get update && \ dmidecode \ libmnl0=1.0.4-2 +RUN pip install \ + pyroute2==0.5.3 + {% if docker_sflow_debs.strip() -%} # Copy locally-built Debian package dependencies {{ copy_files("debs/", docker_sflow_debs.split(' '), "/debs/") }} @@ -30,5 +33,6 @@ RUN sed -ri '/^DAEMON_ARGS=""/c DAEMON_ARGS="-c /var/log/hsflowd.crash"' /etc/in COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] COPY ["critical_processes", "/etc/supervisor"] +COPY ["port_index_mapper.py", "/usr/bin"] ENTRYPOINT ["/usr/bin/supervisord"] diff --git a/dockers/docker-sflow/port_index_mapper.py b/dockers/docker-sflow/port_index_mapper.py new file mode 100755 index 000000000000..a717fcf0da87 --- /dev/null +++ b/dockers/docker-sflow/port_index_mapper.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python + +""" port_index_mapper + A mapper service that watches for NetLink NEWLINK and DELLINKs + to construct a PORT_INDEX_TABLE in state DB which includes the + interface name, the interface index and the ifindex. + + Note : Currently supports only interfaces supported by port_util. +""" + +import os +import sys +import syslog +import signal +import traceback +from pyroute2 import IPDB +from swsssdk import SonicV2Connector, port_util + +RTM_NEWLINK = 16 +RTM_DELLINK = 17 + +PORT_INDEX_TABLE_NAME = 'PORT_INDEX_TABLE' +SYSLOG_IDENTIFIER = 'port_index_mapper' + +ipdb = None +state_db = None + +def interface_callback(ipdb, nlmsg, action): + global state_db + + try: + msgtype = nlmsg['header']['type'] + if (msgtype != RTM_NEWLINK and msgtype != RTM_DELLINK): + return + + # filter out unwanted messages + change = nlmsg['change'] + if (change != 0xFFFFFFFF): + return + + attrs = nlmsg['attrs'] + for list in attrs: + if list[0] == 'IFLA_IFNAME': + ifname = list[1] + break + else: + return + + # Extract the port index from the interface name + index = port_util.get_index_from_str(ifname) + if index is None: + return + + _hash = '{}|{}'.format(PORT_INDEX_TABLE_NAME, ifname) + + if msgtype == RTM_NEWLINK: + state_db.set(state_db.STATE_DB, _hash, 'index', str(index)) + state_db.set(state_db.STATE_DB, _hash, 'ifindex', nlmsg['index']) + elif msgtype == RTM_DELLINK: + state_db.delete(state_db.STATE_DB, _hash) + + except Exception, e: + t = sys.exc_info()[2] + traceback.print_tb(t) + syslog.syslog(syslog.LOG_CRIT, "%s" % str(e)) + os.kill(os.getpid(), signal.SIGTERM) + +def main(): + global state_db, ipdb + state_db = SonicV2Connector(host='127.0.0.1') + state_db.connect(state_db.STATE_DB, False) + + ipdb = IPDB() + + # Initialize the table at startup. + ifnames = ipdb.by_name.keys() + for ifname in ifnames: + index = port_util.get_index_from_str(ifname) + if index is None: + continue + ifindex = ipdb.interfaces[ifname]['index'] + _hash = '{}|{}'.format(PORT_INDEX_TABLE_NAME, ifname) + state_db.set(state_db.STATE_DB, _hash, 'index', str(index)) + state_db.set(state_db.STATE_DB, _hash, 'ifindex', str(ifindex)) + + ipdb.register_callback(interface_callback) + + signal.pause() + +def signal_handler(signum, frame): + syslog.syslog(syslog.LOG_NOTICE, "got signal %d" % signum) + sys.exit(0) + +if __name__ == '__main__': + rc = 0 + try: + syslog.openlog(SYSLOG_IDENTIFIER) + signal.signal(signal.SIGTERM, signal_handler) + signal.signal(signal.SIGINT, signal_handler) + main() + except Exception, e: + t = sys.exc_info()[2] + traceback.print_tb(t) + syslog.syslog(syslog.LOG_CRIT, "%s" % str(e)) + rc = -1 + finally: + if ipdb is not None: + ipdb.release() + else: + syslog.syslog(syslog.LOG_ERR, "ipdb undefined in signal_handler") + + syslog.closelog() + sys.exit(rc) + diff --git a/dockers/docker-sflow/supervisord.conf b/dockers/docker-sflow/supervisord.conf index 3605e50318dc..a3150f23afb3 100644 --- a/dockers/docker-sflow/supervisord.conf +++ b/dockers/docker-sflow/supervisord.conf @@ -35,3 +35,13 @@ stdout_logfile=syslog stderr_logfile=syslog dependent_startup=true dependent_startup_wait_for=rsyslogd:running + +[program:port_index_mapper] +command=/usr/bin/port_index_mapper.py +priority=3 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=rsyslogd:running