# ("NetDEF") in this file.
#
+import functools
import ipaddress
import json
import os
import subprocess
import sys
import traceback
-import functools
from collections import OrderedDict
from copy import deepcopy
from datetime import datetime, timedelta
from lib.topogen import TopoRouter, get_topogen
from lib.topolog import get_logger, logger
from lib.topotest import frr_unicode, interface_set_status, version_cmp
-from lib import topotest
from munet.testing.util import pause_test
+from lib import topotest
+
FRRCFG_FILE = "frr_json.conf"
FRRCFG_BKUP_FILE = "frr_json_initial.conf"
logger.debug("result %s", result)
-def tcpdump_capture_start(
- tgen,
- router,
- intf,
- protocol=None,
- grepstr=None,
- timeout=0,
- options=None,
- cap_file=None,
- background=True,
-):
- """
- API to capture network packets using tcp dump.
-
- Packages used :
-
- Parameters
- ----------
- * `tgen`: topogen object.
- * `router`: router on which ping has to be performed.
- * `intf` : interface for capture.
- * `protocol` : protocol for which packet needs to be captured.
- * `grepstr` : string to filter out tcp dump output.
- * `timeout` : Time for which packet needs to be captured.
- * `options` : options for TCP dump, all tcpdump options can be used.
- * `cap_file` : filename to store capture dump.
- * `background` : Make tcp dump run in back ground.
-
- Usage
- -----
- tcpdump_result = tcpdump_dut(tgen, 'r2', intf, protocol='tcp', timeout=20,
- options='-A -vv -x > r2bgp.txt ')
- Returns
- -------
- 1) True for successful capture
- 2) errormsg - when tcp dump fails
- """
-
- logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
-
- rnode = tgen.gears[router]
-
- if timeout > 0:
- cmd = "timeout {}".format(timeout)
- else:
- cmd = ""
-
- cmdargs = "{} tcpdump".format(cmd)
-
- if intf:
- cmdargs += " -i {}".format(str(intf))
- if protocol:
- cmdargs += " {}".format(str(protocol))
- if options:
- cmdargs += " -s 0 {}".format(str(options))
-
- if cap_file:
- file_name = os.path.join(tgen.logdir, router, cap_file)
- cmdargs += " -w {}".format(str(file_name))
- # Remove existing capture file
- rnode.run("rm -rf {}".format(file_name))
-
- if grepstr:
- cmdargs += ' | grep "{}"'.format(str(grepstr))
-
- logger.info("Running tcpdump command: [%s]", cmdargs)
- if not background:
- rnode.run(cmdargs)
- else:
- # XXX this & is bogus doesn't work
- # rnode.run("nohup {} & /dev/null 2>&1".format(cmdargs))
- rnode.run("nohup {} > /dev/null 2>&1".format(cmdargs))
-
- # Check if tcpdump process is running
- if background:
- result = rnode.run("pgrep tcpdump")
- logger.debug("ps -ef | grep tcpdump \n {}".format(result))
-
- if not result:
- errormsg = "tcpdump is not running {}".format("tcpdump")
- return errormsg
- else:
- logger.info("Packet capture started on %s: interface %s", router, intf)
-
- logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
- return True
-
-
-def tcpdump_capture_stop(tgen, router):
- """
- API to capture network packets using tcp dump.
-
- Packages used :
-
- Parameters
- ----------
- * `tgen`: topogen object.
- * `router`: router on which ping has to be performed.
- * `intf` : interface for capture.
- * `protocol` : protocol for which packet needs to be captured.
- * `grepstr` : string to filter out tcp dump output.
- * `timeout` : Time for which packet needs to be captured.
- * `options` : options for TCP dump, all tcpdump options can be used.
- * `cap2file` : filename to store capture dump.
- * `bakgrnd` : Make tcp dump run in back ground.
-
- Usage
- -----
- tcpdump_result = tcpdump_dut(tgen, 'r2', intf, protocol='tcp', timeout=20,
- options='-A -vv -x > r2bgp.txt ')
- Returns
- -------
- 1) True for successful capture
- 2) errormsg - when tcp dump fails
- """
-
- logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
-
- rnode = tgen.gears[router]
-
- # Check if tcpdump process is running
- result = rnode.run("ps -ef | grep tcpdump")
- logger.debug("ps -ef | grep tcpdump \n {}".format(result))
-
- if not re_search(r"{}".format("tcpdump"), result):
- errormsg = "tcpdump is not running {}".format("tcpdump")
- return errormsg
- else:
- # XXX this doesn't work with micronet
- ppid = tgen.net.nameToNode[rnode.name].pid
- rnode.run("set +m; pkill -P %s tcpdump &> /dev/null" % ppid)
- logger.info("Stopped tcpdump capture")
-
- logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
- return True
-
-
def create_debug_log_config(tgen, input_dict, build=False):
"""
Enable/disable debug logs for any protocol with defined debug
return True
-def socat_send_mld_join(
- tgen,
- server,
- protocol_option,
- mld_groups,
- send_from_intf,
- send_from_intf_ip=None,
- port=12345,
- reuseaddr=True,
-):
- """
- API to send MLD join using SOCAT tool
-
- Parameters:
- -----------
- * `tgen` : Topogen object
- * `server`: iperf server, from where IGMP join would be sent
- * `protocol_option`: Protocol options, ex: UDP6-RECV
- * `mld_groups`: IGMP group for which join has to be sent
- * `send_from_intf`: Interface from which join would be sent
- * `send_from_intf_ip`: Interface IP, default is None
- * `port`: Port to be used, default is 12345
- * `reuseaddr`: True|False, bydefault True
-
- returns:
- --------
- errormsg or True
- """
-
- logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
-
- rnode = tgen.routers()[server]
- socat_args = "socat -u "
-
- # UDP4/TCP4/UDP6/UDP6-RECV/UDP6-SEND
- if protocol_option:
- socat_args += "{}".format(protocol_option)
-
- if port:
- socat_args += ":{},".format(port)
-
- if reuseaddr:
- socat_args += "{},".format("reuseaddr")
-
- # Group address range to cover
- if mld_groups:
- if not isinstance(mld_groups, list):
- mld_groups = [mld_groups]
-
- for mld_group in mld_groups:
- socat_cmd = socat_args
- join_option = "ipv6-join-group"
-
- if send_from_intf and not send_from_intf_ip:
- socat_cmd += "{}='[{}]:{}'".format(join_option, mld_group, send_from_intf)
- else:
- socat_cmd += "{}='[{}]:{}:[{}]'".format(
- join_option, mld_group, send_from_intf, send_from_intf_ip
- )
-
- socat_cmd += " STDOUT"
-
- socat_cmd += " &>{}/socat.logs &".format(tgen.logdir)
-
- # Run socat command to send IGMP join
- logger.info("[DUT: {}]: Running command: [{}]".format(server, socat_cmd))
- output = rnode.run("set +m; {} echo $!".format(socat_cmd))
-
- # Check if socat join process is running
- if output:
- pid = output.split()[0]
- rnode.run("touch /var/run/frr/socat_join.pid")
- rnode.run("echo %s >> /var/run/frr/socat_join.pid" % pid)
- else:
- errormsg = "Socat join is not sent for {}. Error {}".format(
- mld_group, output
- )
- logger.error(output)
- return errormsg
-
- logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
- return True
-
-
-def socat_send_pim6_traffic(
- tgen,
- server,
- protocol_option,
- mld_groups,
- send_from_intf,
- port=12345,
- multicast_hops=True,
-):
- """
- API to send pim6 data taffic using SOCAT tool
-
- Parameters:
- -----------
- * `tgen` : Topogen object
- * `server`: iperf server, from where IGMP join would be sent
- * `protocol_option`: Protocol options, ex: UDP6-RECV
- * `mld_groups`: MLD group for which join has to be sent
- * `send_from_intf`: Interface from which join would be sent
- * `port`: Port to be used, default is 12345
- * `multicast_hops`: multicast-hops count, default is 255
-
- returns:
- --------
- errormsg or True
- """
-
- logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
-
- rnode = tgen.routers()[server]
- socat_args = "socat -u STDIO "
-
- # UDP4/TCP4/UDP6/UDP6-RECV/UDP6-SEND
- if protocol_option:
- socat_args += "'{}".format(protocol_option)
-
- # Group address range to cover
- if mld_groups:
- if not isinstance(mld_groups, list):
- mld_groups = [mld_groups]
-
- for mld_group in mld_groups:
- socat_cmd = socat_args
- if port:
- socat_cmd += ":[{}]:{},".format(mld_group, port)
-
- if send_from_intf:
- socat_cmd += "interface={0},so-bindtodevice={0},".format(send_from_intf)
-
- if multicast_hops:
- socat_cmd += "multicast-hops=255'"
-
- socat_cmd += " >{}/socat.logs &".format(tgen.logdir)
-
- # Run socat command to send pim6 traffic
- logger.info(
- "[DUT: {}]: Running command: [set +m; ( while sleep 1; do date; done ) | {}]".format(
- server, socat_cmd
- )
- )
-
- # Open a shell script file and write data to it, which will be
- # used to send pim6 traffic continously
- traffic_shell_script = "{}/{}/traffic.sh".format(tgen.logdir, server)
- with open("{}".format(traffic_shell_script), "w") as taffic_sh:
- taffic_sh.write(
- "#!/usr/bin/env bash\n( while sleep 1; do date; done ) | {}\n".format(
- socat_cmd
- )
- )
-
- rnode.run("chmod 755 {}".format(traffic_shell_script))
- output = rnode.run("{} &>/dev/null & echo $!".format(traffic_shell_script))
-
- # Check if socat traffic process is running
- if output:
- pid = output.split()[0]
- rnode.run("touch /var/run/frr/socat_traffic.pid")
- rnode.run("echo %s >> /var/run/frr/socat_traffic.pid" % pid)
-
- else:
- errormsg = "Socat traffic is not sent for {}. Error {}".format(
- mld_group, output
- )
- logger.error(output)
- return errormsg
-
- logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
- return True
-
-
-def kill_socat(tgen, dut=None, action=None):
- """
- Killing socat process if running for any router in topology
-
- Parameters:
- -----------
- * `tgen` : Topogen object
- * `dut` : Any iperf hostname to send igmp prune
- * `action`: to kill mld join using socat
- to kill mld traffic using socat
-
- Usage:
- ------
- kill_socat(tgen, dut ="i6", action="remove_mld_join")
-
- """
-
- logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
-
- router_list = tgen.routers()
- for router, rnode in router_list.items():
- if dut is not None and router != dut:
- continue
-
- traffic_shell_script = "{}/{}/traffic.sh".format(tgen.logdir, router)
- pid_socat_join = rnode.run("cat /var/run/frr/socat_join.pid")
- pid_socat_traffic = rnode.run("cat /var/run/frr/socat_traffic.pid")
- if action == "remove_mld_join":
- pids = pid_socat_join
- elif action == "remove_mld_traffic":
- pids = pid_socat_traffic
- else:
- pids = "\n".join([pid_socat_join, pid_socat_traffic])
-
- if os.path.exists(traffic_shell_script):
- cmd = (
- "ps -ef | grep %s | awk -F' ' '{print $2}' | xargs kill -9"
- % traffic_shell_script
- )
- logger.debug("[DUT: {}]: Running command: [{}]".format(router, cmd))
- rnode.run(cmd)
-
- for pid in pids.split("\n"):
- pid = pid.strip()
- if pid.isdigit():
- cmd = "set +m; kill -9 %s &> /dev/null" % pid
- logger.debug("[DUT: {}]: Running command: [{}]".format(router, cmd))
- rnode.run(cmd)
-
- logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
-
-
#############################################
# Verification APIs
#############################################