diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index da7cdd8a2744..53df1c130a72 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -494,6 +494,11 @@ sudo cp $IMAGE_CONFIGS/copp/copp-config.sh $FILESYSTEM_ROOT/usr/bin/ sudo cp $IMAGE_CONFIGS/copp/copp_cfg.j2 $FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES/ echo "copp-config.service" | sudo tee -a $GENERATED_SERVICE_FILE +# Copy DHCP DoS logger configuration files +sudo cp $IMAGE_CONFIGS/dhcp_dos_logger/dhcp_dos_logger.service $FILESYSTEM_ROOT_USR_LIB_SYSTEMD_SYSTEM +sudo cp $IMAGE_CONFIGS/dhcp_dos_logger/dhcp_dos_logger.py $FILESYSTEM_ROOT/usr/bin/ +echo "dhcp_dos_logger.service" | sudo tee -a $GENERATED_SERVICE_FILE + # Copy dhcp client configuration template and create an initial configuration sudo cp files/dhcp/dhclient.conf.j2 $FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES/ j2 files/dhcp/dhclient.conf.j2 | sudo tee $FILESYSTEM_ROOT/etc/dhcp/dhclient.conf diff --git a/files/image_config/dhcp_dos_logger/dhcp_dos_logger.py b/files/image_config/dhcp_dos_logger/dhcp_dos_logger.py new file mode 100644 index 000000000000..96d42e7c70c9 --- /dev/null +++ b/files/image_config/dhcp_dos_logger/dhcp_dos_logger.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +import re +import os +import subprocess +import time +from sonic_py_common.logger import Logger +from swsscommon.swsscommon import ConfigDBConnector + +SYSLOG_IDENTIFIER = os.path.basename(__file__) + +# Global logger instance +logger = Logger(SYSLOG_IDENTIFIER) +logger.log_info("Starting DHCP DoS logger...") + +# Connect to config db +config_db = ConfigDBConnector() +config_db.connect() + +# Initialize +drop_pkts = {} + +# Get list of ports +ports = config_db.get_table('PORT').keys() + +# Initialize the ports with zero initial packet drops +drop_pkts = {port: 0 for port in ports} + +# Main handler function +def handler(): + """ + Continuously monitors ports for dropped DHCP packets and logs them. + """ + while True: + for port in drop_pkts.keys(): + try: + output = subprocess.run(["tc", "-s", "qdisc", "show", "dev", str(port), "handle", "ffff:"], capture_output=True) + if output.returncode == 0: # Check for successful execution + match = re.search(r'dropped (\d+)', output.stdout) + if match: + dropped_count = int(match.group(1)) + if dropped_count > drop_pkts[port]: + logger.log_warning(f"Port {port}: Current DHCP drop counter is {dropped_count}") + drop_pkts[port] = dropped_count + else: + pass + else: + logger.log_warning(f"Failed to get dropped packet information for port {port}") + except subprocess.CalledProcessError as e: + logger.log_error(f"Error executing 'tc' command: {e}") + + time.sleep(10) + + +# Entry point function +def main(): + """ + Entry point for the daemon. + """ + handler() + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/files/image_config/dhcp_dos_logger/dhcp_dos_logger.service b/files/image_config/dhcp_dos_logger/dhcp_dos_logger.service new file mode 100644 index 000000000000..6839e94ae64c --- /dev/null +++ b/files/image_config/dhcp_dos_logger/dhcp_dos_logger.service @@ -0,0 +1,14 @@ +[Unit] +Description=Log DHCP rate limit violations +Requires=config-setup.service +After=config-setup.service +BindsTo=sonic.target +After=sonic.target +After=network.target + +[Service] +Type=simple +ExecStart= /usr/bin/dhcp_dos_logger.py +[Install] +WantedBy=sonic.target +