install: rewrite install script

* set dependency versions: PPA, git repository & commit
* separate download and build+install steps
* don't reinstall package if it's already installed

refs #4630

Change-Id: I966fac5e1633cbabf78ce20cd151a35618efc345
diff --git a/.gitignore b/.gitignore
index a02d875..ee70e67 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,10 +11,8 @@
 
 # Misc
 .DS_Store
-mininet
-mn_wifi
-ndn-src
-openflow
+dl
+*.apconf
 
 # Vagrant
 .vagrant
diff --git a/README.md b/README.md
index 5a1d007..02ba988 100644
--- a/README.md
+++ b/README.md
@@ -27,6 +27,6 @@
 Please refer to http://minindn.memphis.edu/ or [docs/index.rst](docs/index.rst) for installation, usage, and other documentation.
 The documentation can be built using:
 
-    ./install.sh -d
+    ./docs/build.sh
 
 and is available under `docs/_build/html`.
diff --git a/docs/build.sh b/docs/build.sh
new file mode 100755
index 0000000..1b1594a
--- /dev/null
+++ b/docs/build.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+# -*- Mode:bash; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+#
+# Copyright (C) 2015-2021, The University of Memphis,
+#                          Arizona Board of Regents,
+#                          Regents of the University of California.
+#
+# This file is part of Mini-NDN.
+# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
+#
+# Mini-NDN is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mini-NDN is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mini-NDN, e.g., in COPYING.md file.
+# If not, see <http://www.gnu.org/licenses/>.
+
+set -eo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")"
+
+PIP='python3 -m pip'
+
+for PIPPKG in sphinx sphinx_rtd_theme; do
+  if ! $PIP show $PIPPKG >/dev/null; then
+    sudo $PIP install $PIPPKG
+  fi
+done
+
+make clean html
diff --git a/docs/install.rst b/docs/install.rst
index 9073622..40da6b3 100644
--- a/docs/install.rst
+++ b/docs/install.rst
@@ -4,11 +4,13 @@
 Prerequisites
 -------------
 
-For this guide, you will need a laptop/desktop with a recent version of
-a Linux distro that is supported by Mininet. For this guide, the *Ubuntu 18.04 LTS* release was used.
-Some tweaks maybe required to Mini-NDN's install.sh file for other distros.
-Note that you'll need administrative privileges in order to download and install
-extra packages and also to execute **Mini-NDN**.
+Mini-NDN is tested on the following Linux distributions:
+
+- Ubuntu 20.04 (recommended)
+- Debian 11 (WiFi scenario does not work)
+- Fedora 33 (WiFi scenario does not work)
+
+You must have sudo privileges to install and run Mini-NDN.
 
 Using Vagrantfile
 -----------------
@@ -21,66 +23,56 @@
 Using install.sh
 ----------------
 
-Mini-NDN depends on Mininet and NDN software to be installed in the system.
-If you have all the dependencies (see sections below) **installed in the system** simply
-clone this repository and run:
+Mini-NDN has the following dependencies:
+
+- `NDN Forwarding Daemon (NFD) <https://named-data.net/doc/NFD/>`_
+- `Named Data Link State Routing (NLSR) <https://named-data.net/doc/NLSR/>`_
+- `NDN Essential Tools (ndn-tools) <https://github.com/named-data/ndn-tools>`_
+- `NDN Traffic Generator <https://github.com/named-data/ndn-traffic-generator>`_
+- `infoedit <https://github.com/NDN-Routing/infoedit>`_
+- `Mininet <http://mininet.org/>`_
+- `Mininet-WiFi <https://mininet-wifi.github.io/>`_ (optional)
+
+To install Mini-NDN and its dependencies, clone this repository and run:
 
 ::
 
-    ./install.sh -i
+    ./install.sh
 
-The ``-i`` option uses ``setup.py develop`` to point the system install
-to the current directory. So any changes made to the cloned ``mini-ndn``
-folder will be used without having to install it again to the system.
-If you do not need to modify the core of Mini-NDN, then setup.py install (or pip install .)
-can be used directly. See :doc:`experiment <experiment>` for more information on running.
+The script accepts various command line flags.
+Some notable flags are:
 
-If you don't have the dependencies, the following command will
-install them from source along with Mini-NDN. The dependencies include
-Mininet, NDN core (ndn-cxx, NFD, Chronosync, PSync, NLSR), Infoedit,
-and NDN Common Client Libraries (CCL). If you do not wish to install
-the master versions of the NDN core or want to switch to specific versions,
-you can edit the install.sh with release tags/specific versions.
+- ``-y`` skips interactive confirmation before installation.
+- ``--ppa`` prefers installing NDN software from `named-data PPA <https://launchpad.net/~named-data/+archive/ubuntu/ppa>`_.
+  This shortens installation time by downloading binary packages, but is only available on Ubuntu.
+- ``--source`` prefers installing NDN software from source code.
+- ``--dummy-keychain`` patches ndn-cxx to use an in-memory dummy KeyChain, which reduces CPU overhead
+  and allows you to scale up Mini-NDN experiments. Large Mini-NDN experiments would run significantly
+  faster after applying this patch. However, your experiments cannot use any NDN security related
+  features (signatures, verifier, access control, etc).
+- ``--no-wifi`` skips Mininet-WiFi dependency.
+  Currently Mininet-WiFi only works on Ubuntu, so that you must specify this option when installing on other distros.
 
-.. _scaling-note:
-.. important::
-    If you wish to scale Mini-NDN experiments and do not have use for security extensions
-    in your emulations, you should apply the ndn-cxx patch given in the ``patches`` folder
-    using ``./install.sh -p`` before running the following commands. The ndn-cxx patch is
-    taken from ndnSIM which provides an in-memory dummy KeyChain to reduce CPU computations.
-    After these patches are applied sleep time after NFD, nfdc, NLSR, etc. is not required
-    making the startup **MUCH** faster and scaling of Mini-NDN **MUCH** better.
+You can see all command line flags by running:
 
 ::
 
-    ./install.sh -a
+    ./install.sh -h
 
-This pulls the NDN software from Github to ``ndn-src`` folder under the project.
+The script uses ``setup.py develop`` to point the system install of Python packages to the codebase
+directory. Therefore, you can modify ``mininet``, ``mininet-wifi``, and ``mini-ndn``, and the
+changes will be reflected immediately.
 
-.. note::
-    If any changes are made to ``ndn-src`` folder, please don't forgot to re-install
-    the sources to the system.
-
-To install without CCL, use:
-
-::
-
-    ./install.sh -mni
-
-To install in "quiet" mode (without user interaction), use:
-
-::
-    ./install.sh -qa
-
-.. note::
-    The order of the flag -q is important to ensure that the environment is ready for
-    a quiet install.
-
-See ``install.sh -h`` for detailed options.
+If NDN software is installed from source code (not PPA), the code is downloaded to ``dl`` directory
+under your ``mini-ndn`` clone. If you modify the source code, you need to manually recompile and
+reinstall the software (``./waf && sudo ./waf install``).
 
 Installing Dependencies
 -----------------------
 
+This section outlines how to install dependnecies manually.
+If you used ``install.sh``, you do not need to perform these steps.
+
 Mininet
 _______
 
diff --git a/install.sh b/install.sh
index e2d9343..1f795de 100755
--- a/install.sh
+++ b/install.sh
@@ -1,7 +1,7 @@
 #!/bin/bash
 # -*- Mode:bash; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
 #
-# Copyright (C) 2015-2020, The University of Memphis,
+# Copyright (C) 2015-2021, The University of Memphis,
 #                          Arizona Board of Regents,
 #                          Regents of the University of California.
 #
@@ -21,393 +21,166 @@
 # You should have received a copy of the GNU General Public License
 # along with Mini-NDN, e.g., in COPYING.md file.
 # If not, see <http://www.gnu.org/licenses/>.
-#
-# This file incorporates work covered by the following copyright and
-# permission notice:
-#
-#   Mininet 2.3.0d1 License
-#
-#   Copyright (c) 2013-2016 Open Networking Laboratory
-#   Copyright (c) 2009-2012 Bob Lantz and The Board of Trustees of
-#   The Leland Stanford Junior University
-#
-#   Original authors: Bob Lantz and Brandon Heller
-#
-#   We are making Mininet available for public use and benefit with the
-#   expectation that others will use, modify and enhance the Software and
-#   contribute those enhancements back to the community. However, since we
-#   would like to make the Software available for broadest use, with as few
-#   restrictions as possible permission is hereby granted, free of charge, to
-#   any person obtaining a copy of this Software to deal in the Software
-#   under the copyrights without restriction, including without limitation
-#   the rights to use, copy, modify, merge, publish, distribute, sublicense,
-#   and/or sell copies of the Software, and to permit persons to whom the
-#   Software is furnished to do so, subject to the following conditions:
-#
-#   The above copyright notice and this permission notice shall be included
-#   in all copies or substantial portions of the Software.
-#
-#   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-#   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-#   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-#   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-#   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-#   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-#   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-#   The name and trademarks of copyright holder(s) may NOT be used in
-#   advertising or publicity pertaining to the Software or any derivatives
-#   without specific, written prior permission.
 
-test -e /etc/debian_version && DIST="Debian"
-grep Ubuntu /etc/lsb-release &> /dev/null && DIST="Ubuntu"
+set -eo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")"
 
-if [[ $DIST == Ubuntu || $DIST == Debian ]]; then
-    update='sudo apt-get update'
-    install='sudo apt-get -y install'
-    remove='sudo apt-get -y remove'
-    pkginst='sudo dpkg -i'
-    # Prereqs for this script
-    if ! which lsb_release &> /dev/null; then
-        $install lsb-release
-    fi
-fi
+# These commands are generally installed on most systems. If not, user must install manually.
+# 'sudo' is not directly used by this script, but Mininet install.sh uses it, so we check that also.
+NEEDED_BINARIES=(
+  awk
+  git
+  sudo
+)
+MISSING_BINARIES=()
 
-test -e /etc/fedora-release && DIST="Fedora"
-if [[ $DIST == Fedora ]]; then
-    update='sudo yum update'
-    install='sudo yum -y install'
-    remove='sudo yum -y erase'
-    pkginst='sudo rpm -ivh'
-    # Prereqs for this script
-    if ! which lsb_release &> /dev/null; then
-        $install redhat-lsb-core
-    fi
-fi
-
-NDN_SRC="ndn-src"
-
-NDN_GITHUB="https://github.com/named-data"
-
-NDN_CXX_VERSION="master"
-NFD_VERSION="master"
-PSYNC_VERSION="master"
-CHRONOSYNC_VERSION="master"
-NLSR_VERSION="master"
-NDN_TOOLS_VERSION="master"
-
-if [ $SUDO_USER ]; then
-    REAL_USER=$SUDO_USER
+SUDO=
+if [[ $(id -u) -eq 0 ]]; then
+  if [[ -n $SUDO_USER ]] && [[ -z $SKIPSUDOCHECK ]]; then
+    cat <<EOT
+Do not run this script through sudo
+Instead, run this script as a regular user; the script will call sudo when needed
+To bypass this check, set the environment variable SKIPSUDOCHECK=1
+EOT
+    exit 1
+  fi
 else
-    REAL_USER=$(whoami)
+  SUDO=sudo
 fi
 
-function patchDummy {
-    git -C $NDN_SRC/ndn-cxx apply $(pwd)/util/patches/ndn-cxx-dummy-keychain-from-ndnsim.patch
-    if [[ "$?" -ne 0 ]]; then
-        echo "Patch might already be applied"
-    fi
-}
-
-function quiet_install {
-    if [[ $DIST == Ubuntu || $DIST == Debian ]]; then
-        update='sudo DEBIAN_FRONTEND=noninteractive apt-get update'
-        install='sudo DEBIAN_FRONTEND=noninteractive apt-get -y install'
-        remove='sudo DEBIAN_FRONTEND=noninteractive apt-get -y remove'
-
-        echo "wireshark-common wireshark-common/install-setuid boolean false" | sudo debconf-set-selections
-    fi
-}
-
-function ndn_install {
-    mkdir -p $NDN_SRC
-    name=$1
-    version=$2
-    wafOptions=$3
-
-    if [[ $version == "master" ]]; then
-        if [[ -d "$NDN_SRC/$name" ]]; then
-            pushd $NDN_SRC/$name
-            git checkout master
-        else
-            git clone --depth 1 $NDN_GITHUB/$name $NDN_SRC/$name
-            pushd $NDN_SRC/$name
-        fi
-    else
-        if [[ -d $NDN_SRC/$name ]]; then
-            pushd $NDN_SRC/$name
-            if [[ $(git rev-parse --is-shallow-repository) == "true" ]]; then
-                git fetch --unshallow
-                git fetch --all
-            fi
-        else
-            git clone $NDN_GITHUB/$name $NDN_SRC/$name
-            pushd $NDN_SRC/$name
-        fi
-        git checkout $version -b version-$version || git checkout version-$version
-    fi
-
-    # User must use the same python version as root to use ./waf outside of this script
-    sudo -E -u $REAL_USER ./waf configure $wafOptions
-    sudo -E -u $REAL_USER ./waf && sudo ./waf install && sudo ldconfig
-    popd
-}
-
-function ndn {
-    if [[ updated != true ]]; then
-        $update
-        updated="true"
-    fi
-
-    if [[ $DIST == Ubuntu || $DIST == Debian ]]; then
-        $install git libsqlite3-dev libboost-all-dev make g++ libssl-dev libpcap-dev pkg-config python-pip
-    fi
-
-    if [[ $DIST == Fedora ]]; then
-        $install gcc-c++ sqlite-devel boost-devel openssl-devel libpcap-devel python-pip
-    fi
-
-    ndn_install ndn-cxx $NDN_CXX_VERSION
-    ndn_install NFD $NFD_VERSION --without-websocket
-    ndn_install PSync $PSYNC_VERSION --with-examples
-    ndn_install ChronoSync $CHRONOSYNC_VERSION
-    ndn_install NLSR $NLSR_VERSION
-    ndn_install ndn-tools $NDN_TOOLS_VERSION
-    infoedit
-}
-
-function mininet {
-    if [[ updated != true ]]; then
-        $update
-        updated="true"
-    fi
-
-    if [[ $pysetup != true ]]; then
-        pysetup="true"
-    fi
-
-    git clone --depth 1 https://github.com/mininet/mininet
-    pushd mininet
-    sudo ./util/install.sh -nv
-    popd
-}
-
-function wifi {
-    if [[ updated != true ]]; then
-        $update
-        updated="true"
-    fi
-
-    if [[ $pysetup != true ]]; then
-        pysetup="true"
-    fi
-
-    git clone --depth 1 https://github.com/intrig-unicamp/mininet-wifi.git
-    pushd mininet-wifi
-    sudo ./util/install.sh -Wlfnv
-    popd
-}
-
-function infoedit {
-    git clone --depth 1 https://github.com/NDN-Routing/infoedit.git $NDN_SRC/infoedit
-    pushd $NDN_SRC/infoedit
-    rm infoedit
-    sudo make install
-    popd
-}
-
-function minindn {
-    $install libigraph0-dev tshark
-    sudo pip install -r requirements.txt
-
-    if [[ updated != true ]]; then
-        if [ ! -d "build" ]; then
-            $update
-            updated="true"
-        fi
-    fi
-
-    if [[ $pysetup != true ]]; then
-        $install python-setuptools
-        pysetup="true"
-    fi
-    install_dir="/usr/local/etc/mini-ndn/"
-
-    sudo mkdir -p "$install_dir"
-    sudo cp topologies/default-topology.conf "$install_dir"
-    sudo cp topologies/minindn.caida.conf "$install_dir"
-    sudo cp topologies/minindn.ucla.conf "$install_dir"
-    sudo cp topologies/minindn.testbed.conf "$install_dir"
-    sudo cp topologies/current-testbed.conf "$install_dir"
-    sudo cp topologies/geo_hyperbolic_test.conf "$install_dir"
-    sudo cp topologies/geant.conf "$install_dir"
-    sudo cp topologies/wifi/singleap-topology.conf "$install_dir"
-    sudo python setup.py develop
-}
-
-function ndn_cpp {
-    if [[ updated != true ]]; then
-        $update
-        updated="true"
-    fi
-
-    if [[ $DIST == Ubuntu || $DIST == Debian ]]; then
-        $install git build-essential libssl-dev libsqlite3-dev libboost-all-dev libprotobuf-dev protobuf-compiler
-    fi
-
-    if [[ $DIST == Fedora ]]; then
-        printf '\nNDN-CPP does not support Fedora yet.\n'
-        return
-    fi
-
-    git clone --depth 1 $NDN_GITHUB/ndn-cpp $NDN_SRC/ndn-cpp
-    pushd $NDN_SRC/ndn-cpp
-    ./configure
-    proc=$(nproc)
-    make -j$proc
-    sudo make install
-    sudo ldconfig
-    popd
-}
-
-function pyNDN {
-    if [[ updated != true ]]; then
-        $update
-        updated="true"
-    fi
-
-    if [[ $DIST == Ubuntu || $DIST == Debian ]]; then
-        $install git build-essential libssl-dev libffi-dev python-dev python-pip
-    fi
-
-    if [[ $DIST == Fedora ]]; then
-        printf '\nPyNDN does not support Fedora yet.\n'
-        return
-    fi
-
-    sudo pip install cryptography trollius protobuf pytest mock
-    git clone --depth 1 $NDN_GITHUB/PyNDN2 $NDN_SRC/PyNDN2
-    pushd $NDN_SRC/PyNDN2
-    # Update the user's PYTHONPATH.
-    echo "export PYTHONPATH=\$PYTHONPATH:`pwd`/python" >> ~/.bashrc
-    # Also update root's PYTHONPATH in case of running under sudo.
-    echo "export PYTHONPATH=\$PYTHONPATH:`pwd`/python" | sudo tee -a /root/.bashrc > /dev/null
-    popd
-}
-
-function ndn_js {
-    if [[ updated != true ]]; then
-        $update
-        updated="true"
-    fi
-
-    if [[ $DIST == Ubuntu || $DIST == Debian ]]; then
-        $install git nodejs npm
-    fi
-
-    if [[ $DIST == Fedora ]]; then
-        printf '\nNDN-JS does not support Fedora yet.\n'
-        return
-    fi
-
-    sudo ln -fs /usr/bin/nodejs /usr/bin/node
-    sudo npm install -g mocha
-    sudo npm install rsa-keygen sqlite3
-    git clone --depth 1 $NDN_GITHUB/ndn-js $NDN_SRC/ndn-js
-}
-
-function jNDN {
-    if [[ updated != true ]]; then
-        $update
-        updated="true"
-    fi
-
-    if [[ $DIST == Ubuntu || $DIST == Debian ]]; then
-        $install git openjdk-8-jdk maven
-    fi
-
-    if [[ $DIST == Fedora ]]; then
-        printf '\nNDN-JS does not support Fedora yet.\n'
-        return
-    fi
-
-    git clone --depth 1 $NDN_GITHUB/jndn $NDN_SRC/jndn
-    pushd $NDN_SRC/jndn
-    mvn install
-    popd
-}
-
-function commonClientLibraries {
-    ndn_cpp
-    pyNDN
-    ndn_js
-    jNDN
-}
-
-function buildDocumentation {
-    sphinxInstalled=$(pip show sphinx | wc -l)
-    sphinxRtdInstalled=$(pip show sphinx_rtd_theme | wc -l)
-    if [[ $sphinxInstalled -eq "0" ]]; then
-        pip install sphinx
-    fi
-
-    if [[ $sphinxRtdInstalled -eq "0" ]]; then
-        pip install sphinx_rtd_theme
-    fi
-    cd docs
-    make clean
-    make html
-}
-
-function usage {
-    printf '\nUsage: %s [-a]\n\n' $(basename $0) >&2
-
-    printf 'options:\n' >&2
-    printf -- ' -a: install all the required dependencies\n' >&2
-    printf -- ' -A: install all the required dependencies (wired only)\n' >&2
-    printf -- ' -c: install Common Client Libraries\n' >&2
-    printf -- ' -d: build documentation\n' >&2
-    printf -- ' -h: print this (H)elp message\n' >&2
-    printf -- ' -i: install mini-ndn\n' >&2
-    printf -- ' -m: install mininet and dependencies (for wired-only installation)\n' >&2
-    printf -- ' -n: install NDN dependencies of mini-ndn including infoedit\n' >&2
-    printf -- ' -p: patch ndn-cxx with dummy key chain\n' >&2
-    printf -- ' -q: quiet install (must be specified first)\n' >&2
-    printf -- ' -w: install mininet-wifi and dependencies\n' >&2
-    exit 2
-}
-
-if [[ $# -eq 0 ]]; then
-    usage
-else
-    while getopts 'aAcdhimnpqw' OPTION
-    do
-        case $OPTION in
-        a)
-        ndn
-        wifi
-        minindn
-        commonClientLibraries
-        break
-        ;;
-        A)
-        ndn
-        mininet
-        minindn
-        commonClientLibraries
-        break
-        ;;
-        c)    commonClientLibraries;;
-        d)    buildDocumentation;;
-        h)    usage;;
-        i)    minindn;;
-        m)    mininet;;
-        n)    ndn;;
-        p)    patchDummy;;
-        q)    quiet_install;;
-        w)    wifi ;;
-        ?)    usage;;
-        esac
-    done
-    shift $(($OPTIND - 1))
+for B in "${NEEDED_BINARIES[@]}"; do
+  if ! command -v "$B" >/dev/null; then
+    MISSING_BINARIES+=("$B")
+  fi
+done
+if [[ ${#MISSING_BINARIES[@]} -gt 0 ]] ; then
+  echo "Missing commands (${MISSING_BINARIES[*]}) to start this script. To install, run:"
+  echo "  $SUDO apt install --no-install-recommends ca-certificates curl git mawk sudo"
+  echo "  $SUDO yum install ca-certificates curl git mawk sudo"
+  exit 1
 fi
+
+CODEROOT="$(pwd)/dl"
+NJOBS=$(nproc)
+MEM_JOBS=$(awk '$1=="MemAvailable:" { print int($2/(1536*1024)); exit }' /proc/meminfo)
+if [[ $MEM_JOBS -lt 1 ]]; then
+  NJOBS=1
+  echo 'Insufficient available RAM, build may fail'
+elif [[ $MEM_JOBS -lt $NJOBS ]]; then
+  NJOBS=$MEM_JOBS
+fi
+PREFER_FROM=ppa
+PPA_PKGS=()
+
+ARGS=$(getopt -o 'hy' -l 'help,dir:,jobs:,no-wifi,ppa,source,cxx:,dummy-keychain,nfd:,psync:,nlsr:,tools:,traffic:,infoedit:,mininet:,mnwifi:,dl-only,ignore-existing' -- "$@")
+eval set -- "$ARGS"
+while true; do
+  case $1 in
+    -h|--help) HELP=1; shift;;
+    -y) CONFIRM=1; shift;;
+    --dir) CODEROOT=$2; shift 2;;
+    --jobs) NJOBS=$((0+$2)); shift 2;;
+    --no-wifi) NO_WIFI=1; shift;;
+    --ppa) PREFER_FROM=ppa; shift;;
+    --source) PREFER_FROM=source; shift;;
+    --cxx) CXX_VERSION=$2; NO_PPA=1; shift 2;;
+    --dummy-keychain) CXX_DUMMY_KEYCHAIN=1; NO_PPA=1; shift;;
+    --nfd) NFD_VERSION=$2; NO_PPA=1; shift 2;;
+    --psync) PSYNC_VERSION=$2; NO_PPA=1; shift 2;;
+    --nlsr) NLSR_VERSION=$2; NO_PPA=1; shift 2;;
+    --tools) TOOLS_VERSION=$2; NO_PPA=1; shift 2;;
+    --traffic) TRAFFIC_VERSION=$2; NO_PPA=1; shift 2;;
+    --infoedit) INFOEDIT_VERSION=$2; shift 2;;
+    --mininet) MININET_VERSION=$2; shift 2;;
+    --mnwifi) MNWIFI_VERSION=$2; shift 2;;
+    --dl-only) DL_ONLY=1; shift;;
+    --ignore-existing) IGNORE_EXISTING=1; shift;;
+    --) shift; break;;
+    *) exit 1;;
+  esac
+done
+
+if [[ $NJOBS -le 0 ]]; then
+  cat <<EOT
+--jobs must be a positive integer.
+Run ./install.sh -h to see help message.
+EOT
+  exit 1
+fi
+
+if [[ $HELP -eq 1 ]]; then
+  cat <<EOT
+./install.sh [OPTION]...
+
+General options:
+  -h  Display help and exit.
+  -y  Skip confirmation.
+  --dir=${CODEROOT}
+      Set where to download and compile the code.
+  --jobs=${NJOBS}
+      Set number of parallel jobs.
+  --no-wifi
+      Do not install Mininet-WiFi.
+
+Install preference options:
+  --ppa
+      Install available packages from named-data PPA.
+      This is the default on Ubuntu, unless a source code version option is used.
+  --source
+      Install all packages from source code.
+
+Source code version options:
+  --cxx=[VERSION]
+      Set ndn-cxx version.
+  --dummy-keychain
+      Patch ndn-cxx to use dummy KeyChain.
+      This disables signing and verifications, which allows experiments to run faster.
+      Use this option only if your scenario does not require signature verification.
+  --nfd=[VERSION]
+      Set NFD version.
+  --psync=[VERSION]
+      Set PSync version.
+  --nlsr=[VERSION]
+      Set NLSR version.
+  --tools=[VERSION]
+      Set NDN Essential Tools version.
+  --traffic=[VERSION]
+      Set NDN Traffic Generator version.
+  --infoedit=[VERSION]
+      Set infoedit version.
+  --mininet=[VERSION]
+      Set Mininet version.
+  --mnwifi=[VERSION]
+      Set Mininet-WiFi version.
+Acceptable version syntaxes:
+  * git commit/tag/branch, example: --nfd=NFD-0.7.1
+  * git repository (e.g. fork) and commit/tag/branch, example:
+      --nfd=https://github.com/named-data/NFD.git@NFD-0.7.1
+  * change,patchset on named-data Gerrit, example: --nfd=6236,8
+
+Misc options:
+  --dl-only
+      Download the source code only.
+      You may modify the code in ${CODEROOT} and then rerun this script to install them.
+  --ignore-existing
+      Ignore already installed binaries and libraries, and attempt to reinstall.
+      This is useful if you have modified source code checkout and want to install again.
+EOT
+  exit 0
+fi
+
+trap 'set +e; trap - ERR; echo "Error!"; exit 1;' ERR
+
+PKGDEPDIR="$(pwd)/util/pkgdep"
+if [[ -e /etc/os-release ]]; then
+  source /etc/os-release
+fi
+for id in ${ID,,} ${ID_LIKE,,}; do
+  if [[ -e $PKGDEPDIR/$id.sh ]]; then
+    source "$PKGDEPDIR/$id.sh"
+    source "$PKGDEPDIR/common.sh"
+    exit 0
+  fi
+done
+echo "Unsupported platform ${ID}, aborting"
+exit 1
diff --git a/minindn/util.py b/minindn/util.py
index b7d060c..23092da 100644
--- a/minindn/util.py
+++ b/minindn/util.py
@@ -27,7 +27,6 @@
 from six.moves.urllib.parse import quote
 
 from mininet.cli import CLI
-from mn_wifi.cli import CLI as CLI_wifi
 
 sshbase = ['ssh', '-q', '-t', '-i/home/mininet/.ssh/id_rsa']
 scpbase = ['scp', '-i', '/home/mininet/.ssh/id_rsa']
@@ -90,7 +89,15 @@
     def __init__(self, mininet, stdin=sys.stdin, script=None):
         CLI.__init__(self, mininet, stdin, script)
 
-class MiniNDNWifiCLI(CLI_wifi):
-    prompt = 'mini-ndn-wifi> '
-    def __init__(self, mininet, stdin=sys.stdin, script=None):
-        CLI_wifi.__init__(self, mininet, stdin, script)
+try:
+    from mn_wifi.cli import CLI as CLI_wifi
+
+    class MiniNDNWifiCLI(CLI_wifi):
+        prompt = 'mini-ndn-wifi> '
+        def __init__(self, mininet, stdin=sys.stdin, script=None):
+            CLI_wifi.__init__(self, mininet, stdin, script)
+
+except ImportError:
+    class MiniNDNWifiCLI:
+        def __init__(self):
+            raise ImportError('Mininet-WiFi is not installed')
diff --git a/util/patches/ndn-cxx-dummy-keychain-from-ndnsim.patch b/util/patches/ndn-cxx-dummy-keychain.patch
similarity index 100%
rename from util/patches/ndn-cxx-dummy-keychain-from-ndnsim.patch
rename to util/patches/ndn-cxx-dummy-keychain.patch
diff --git a/util/pkgdep/common.sh b/util/pkgdep/common.sh
new file mode 100644
index 0000000..9105fa2
--- /dev/null
+++ b/util/pkgdep/common.sh
@@ -0,0 +1,288 @@
+# -*- Mode:bash; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+#
+# Copyright (C) 2015-2021, The University of Memphis,
+#                          Arizona Board of Regents,
+#                          Regents of the University of California.
+#
+# This file is part of Mini-NDN.
+# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
+#
+# Mini-NDN is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mini-NDN is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mini-NDN, e.g., in COPYING.md file.
+# If not, see <http://www.gnu.org/licenses/>.
+
+# needed by Python version detection logic in Mininet & Mininet-WiFi install script
+export PYTHON=python3
+
+# DEP_INFO key should match *_VERSION variable name.
+# DEP_INFO entry should have these comma separated fields:
+# [0] local directory name
+# [1] dep name
+# [2] PPA package name
+# [3] GitHub repository (HTTPS)
+# [4] Gerrit repository (repo name only)
+declare -A DEP_INFO
+DEP_INFO=(
+  ["CXX"]="ndn-cxx,ndn-cxx,libndn-cxx-dev,https://github.com/named-data/ndn-cxx.git,ndn-cxx"
+  ["NFD"]="NFD,NFD,nfd,https://github.com/named-data/NFD.git,NFD"
+  ["PSYNC"]="PSync,PSync,libpsync-dev,https://github.com/named-data/PSync.git,PSync"
+  ["NLSR"]="NLSR,NLSR,nlsr,https://github.com/named-data/NLSR.git,NLSR"
+  ["TOOLS"]="ndn-tools,NDN Essential Tools,ndn-tools,https://github.com/named-data/ndn-tools.git,ndn-tools"
+  ["TRAFFIC"]="ndn-traffic-generator,NDN Traffic Generator,ndn-traffic-generator,https://github.com/named-data/ndn-traffic-generator.git,ndn-traffic-generator"
+  ["INFOEDIT"]="infoedit,infoedit,,https://github.com/NDN-Routing/infoedit.git,"
+  ["MININET"]="mininet,Mininet,,https://github.com/mininet/mininet.git,"
+  ["MNWIFI"]="mininet-wifi,Mininet-WiFi,,https://github.com/intrig-unicamp/mininet-wifi.git,"
+)
+
+# command to detect dependency existence
+# if not specified, dependency is assumed to not exist
+declare -A DEP_DETECT
+DEP_DETECT=(
+  ["CXX"]="pkg-config libndn-cxx"
+  ["NFD"]="command -v nfd"
+  ["PSYNC"]="pkg-config PSync"
+  ["NLSR"]="command -v nlsr"
+  ["TOOLS"]="command -v ndnping && command -v ndncatchunks"
+  ["TRAFFIC"]="command -v ndn-traffic-client"
+  ["INFOEDIT"]="command -v infoedit"
+  ["MININET"]="command -v mn && command -v ofdatapath && $PYTHON -m pip show mininet"
+  ["MNWIFI"]="$PYTHON -m pip show mininet-wifi"
+)
+
+# non-Waf build & install command
+build_INFOEDIT() {
+  make -j${NJOBS}
+  $SUDO make install
+}
+build_MININET() {
+  ./util/install.sh -s ${CODEROOT} -nv
+  if ! command -v ofdatapath >/dev/null; then
+    rm -rf ${CODEROOT}/openflow
+    ./util/install.sh -s ${CODEROOT} -f
+  fi
+
+  $SUDO $PYTHON setup.py develop
+  $SUDO cp /usr/local/bin/mn /usr/local/bin/mn.mininet
+}
+build_MNWIFI() {
+  # issue: util/install.sh attempts to patch hostap every time, causing "Assume -R?" prompt
+  # during reinstalls
+  # workaround: revert hostap repository to clean state
+  $SUDO git -C hostap clean -fdx || true
+  $SUDO git -C hostap checkout -- . || true
+
+  # issue: util/install.sh is not using 'sudo' where needed
+  # solution: run whole script in 'sudo'
+  $SUDO env PYTHON="$PYTHON" ./util/install.sh -Wl
+
+  # issue: setup.py reports "Cannot load backend 'TkAgg' which requires the 'tk' interactive
+  # framework, as 'headless' is currently running" when running over SSH
+  # workaround: pretend to have X11 display
+  $SUDO env DISPLAY=:0 $PYTHON setup.py develop
+  $SUDO cp /usr/local/bin/mn /usr/local/bin/mn.wifi
+
+  # make 'mn' command refer to Mininet's version, which does not require X11
+  if [[ -x /usr/local/bin/mn.mininet ]]; then
+    $SUDO cp /usr/local/bin/mn.mininet /usr/local/bin/mn
+  fi
+}
+
+# Waf configure options
+declare -A DEP_WAFOPTS
+DEP_WAFOPTS=(
+  ["NFD"]="--without-websocket"
+  ["PSYNC"]="--with-examples"
+)
+
+# return whether dep is installed
+dep_exists() {
+  if [[ $IGNORE_EXISTING -eq 1 ]]; then
+    return 2
+  fi
+  local DETECT="${DEP_DETECT[$1]}"
+  if [[ -n $DETECT ]] && bash -c "$DETECT" &>/dev/null; then
+    return 0
+  fi
+  return 1
+}
+
+# set to 1 if dep needs downloading
+declare -A NEED_DL
+
+# display prompt on what to do with dep, populate NEED_DL
+dep_prompt() {
+  local INFO=()
+  IFS=',' read -a INFO <<< "${DEP_INFO[$1]}"
+  local VERSION_VAR="$1_VERSION"
+  local VERSION="${!VERSION_VAR}"
+  if [[ -z $VERSION ]]; then
+    VERSION='(default branch)'
+  fi
+  local DLDIR="${CODEROOT}/${INFO[0]}"
+  if dep_exists $1; then
+    echo "Will use existing ${INFO[1]}"
+  elif [[ $PREFER_FROM == ppa ]] && [[ -n ${INFO[2]} ]]; then
+    echo "Will install ${INFO[1]} from named-data PPA"
+    PPA_PKGS+=("${INFO[2]}")
+  elif [[ -d "$DLDIR" ]]; then
+    if [[ $DL_ONLY -ne 1 ]]; then
+      echo "Will install ${INFO[1]} from local checkout ${DLDIR}"
+    fi
+  else
+    NEED_DL[$1]=1
+    if [[ $DL_ONLY -eq 1 ]]; then
+      echo "Will checkout ${INFO[1]} ${VERSION} to ${DLDIR}"
+    else
+      echo "Will download and install ${INFO[1]} ${VERSION}"
+    fi
+  fi
+}
+
+# download dep source code
+dep_checkout() {
+  if [[ ${NEED_DL[$1]} -ne 1 ]]; then
+    return
+  fi
+  local INFO=()
+  IFS=',' read -a INFO <<< "${DEP_INFO[$1]}"
+  local VERSION_VAR="$1_VERSION"
+  local VERSION="${!VERSION_VAR}"
+  local DLDIR="${CODEROOT}/${INFO[0]}"
+
+  if [[ -n ${INFO[4]} ]] && [[ "$VERSION" =~ ^[0-9]+,[0-9]+$ ]]; then
+    local REPO="https://gerrit.named-data.net/${INFO[4]}"
+    local GERRIT_CHANGE=${VERSION%,*}
+    local GERRIT_PATCHSET=${VERSION#*,}
+    echo "Downloading ${INFO[2]} from Gerrit (patchset ${GERRIT_CHANGE},${GERRIT_PATCHSET})"
+    git clone "$REPO" "$DLDIR"
+    git -C "$DLDIR" fetch origin "refs/changes/${GERRIT_CHANGE:(-2)}/${GERRIT_CHANGE}/${GERRIT_PATCHSET}"
+    git -C "$DLDIR" -c advice.detachedHead=false checkout FETCH_HEAD
+  elif [[ -z $VERSION ]]; then
+    echo "Downloading ${INFO[1]} from GitHub (default branch)"
+    git clone "${INFO[3]}" "$DLDIR"
+  elif [[ "$VERSION" =~ @ ]]; then
+    local REPO=${VERSION%@*}
+    local BRANCH=${VERSION#*@}
+    echo "Downloading ${INFO[1]} from ${REPO} (branch ${BRANCH})"
+    git clone "$REPO" "$DLDIR"
+    git -C "$DLDIR" -c advice.detachedHead=false checkout "$BRANCH"
+  else
+    echo "Downloading ${INFO[1]} from GitHub (branch ${VERSION})"
+    git clone "${INFO[3]}" "$DLDIR"
+    git -C "$DLDIR" -c advice.detachedHead=false checkout "$VERSION"
+  fi
+  git submodule update --init --recursive --progress
+}
+
+# install dep from source code
+dep_install() {
+  local INFO=()
+  IFS=',' read -a INFO <<< "${DEP_INFO[$1]}"
+  local DLDIR="${CODEROOT}/${INFO[0]}"
+  if dep_exists $1 || ! [[ -d "$DLDIR" ]]; then
+    return
+  fi
+  pushd "$DLDIR"
+
+  local FN="build_$1"
+  if declare -F $FN >/dev/null; then
+    echo "Installing ${INFO[1]} with custom command"
+    $FN
+  elif [[ -x waf ]]; then
+    echo "Installing ${INFO[1]} with Waf"
+    $PYTHON ./waf configure ${DEP_WAFOPTS[$1]}
+    $PYTHON ./waf -j${NJOBS}
+    $SUDO $PYTHON ./waf install
+  fi
+  popd
+}
+
+if [[ $PPA_AVAIL -ne 1 ]] || [[ $NO_PPA -eq 1 ]]; then
+  PREFER_FROM=source
+fi
+
+# dep install order, excluding ndn-cxx
+DEPLIST=(NFD PSYNC NLSR TOOLS TRAFFIC INFOEDIT MININET)
+if [[ $NO_WIFI -ne 1 ]]; then
+  DEPLIST+=(MNWIFI)
+fi
+
+echo "Will download to ${CODEROOT}"
+echo 'Will install compiler and build tools'
+dep_prompt CXX
+if [[ $CXX_DUMMY_KEYCHAIN -eq 1 ]]; then
+  echo 'Will patch ndn-cxx to use dummy KeyChain'
+fi
+for DEP in "${DEPLIST[@]}"; do
+  dep_prompt $DEP
+done
+if [[ $DL_ONLY -ne 1 ]]; then
+  echo "Will compile with ${NJOBS} parallel jobs"
+  echo "Will install Mini-NDN package"
+fi
+
+if [[ $CONFIRM -ne 1 ]]; then
+  read -p 'Press ENTER to continue or CTRL+C to abort '
+fi
+
+install_pkgs
+
+if [[ -z $SKIPPYTHONCHECK ]]; then
+  PYTHON_VERSION=$($PYTHON --version)
+  SUDO_PYTHON_VERSION=$($SUDO $PYTHON --version)
+  if [[ "$PYTHON_VERSION" != "$SUDO_PYTHON_VERSION" ]]; then
+    cat <<EOT
+In your system, '${PYTHON}' is ${PYTHON_VERSION} and '$SUDO ${PYTHON}' is ${SUDO_PYTHON_VERSION}
+You must manually resolve the conflict, e.g. delete excess Python installation or change $PATH
+To bypass this check, set the environment variable SKIPPYTHONCHECK=1
+EOT
+    exit 1
+  fi
+fi
+
+if ! mkdir -p "${CODEROOT}" 2>/dev/null; then
+  $SUDO mkdir -p "${CODEROOT}"
+  $SUDO chown $(id -u) "${CODEROOT}"
+fi
+dep_checkout CXX
+if [[ $CXX_DUMMY_KEYCHAIN -eq 1 ]]; then
+  echo 'Patching ndn-cxx to use dummy KeyChain'
+  if ! git -C "${CODEROOT}/ndn-cxx" apply --index < "${PKGDEPDIR}/../patches/ndn-cxx-dummy-keychain.patch"; then
+    echo 'Cannot patch ndn-cxx to use dummy KeyChain (possibly already patched)'
+  fi
+fi
+for DEP in "${DEPLIST[@]}"; do
+  dep_checkout $DEP
+done
+
+if [[ $DL_ONLY -eq 1 ]]; then
+  cat <<EOT
+Source code has been downloaded to ${CODEROOT}
+You may make changes or checkout different versions
+Run this script again without --dl-only to install from local checkout
+EOT
+  exit 0
+fi
+
+prepare_ld
+for DEP in CXX "${DEPLIST[@]}"; do
+  dep_install $DEP
+done
+$SUDO ldconfig
+
+DESTDIR=/usr/local/etc/mini-ndn
+$SUDO install -d -m0755 "$DESTDIR"
+find topologies/ -name '*.conf' | xargs $SUDO install -m0644 -t "$DESTDIR/"
+$SUDO $PYTHON setup.py develop
+
+echo 'MiniNDN installation completed successfully'
diff --git a/util/pkgdep/debian-like.sh b/util/pkgdep/debian-like.sh
new file mode 100644
index 0000000..52fb9a5
--- /dev/null
+++ b/util/pkgdep/debian-like.sh
@@ -0,0 +1,66 @@
+# -*- Mode:bash; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+#
+# Copyright (C) 2015-2021, The University of Memphis,
+#                          Arizona Board of Regents,
+#                          Regents of the University of California.
+#
+# This file is part of Mini-NDN.
+# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
+#
+# Mini-NDN is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mini-NDN is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mini-NDN, e.g., in COPYING.md file.
+# If not, see <http://www.gnu.org/licenses/>.
+
+# APT packages, written in alphabetical order.
+APT_PKGS=(
+  build-essential
+  ca-certificates
+  git
+  libboost-atomic-dev
+  libboost-chrono-dev
+  libboost-date-time-dev
+  libboost-filesystem-dev
+  libboost-iostreams-dev
+  libboost-log-dev
+  libboost-program-options-dev
+  libboost-regex-dev
+  libboost-stacktrace-dev
+  libboost-system-dev
+  libboost-thread-dev
+  libpcap-dev
+  libsqlite3-dev
+  libssl-dev
+  libsystemd-dev
+  pkg-config
+  python-is-python3
+  python3-pip
+  software-properties-common
+  tshark
+)
+
+if [[ $NO_WIFI -ne 1 ]]; then
+  APT_PKGS+=(network-manager)
+fi
+
+install_pkgs() {
+  $SUDO apt-get update
+  $SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "${APT_PKGS[@]}"
+  if [[ $PPA_AVAIL -eq 1 ]] && [[ ${#PPA_PKGS[@]} -gt 0 ]]; then
+    $SUDO add-apt-repository -y -u ppa:named-data/ppa
+    $SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "${PPA_PKGS[@]}"
+  fi
+}
+
+prepare_ld() {
+  return
+}
diff --git a/util/pkgdep/debian.sh b/util/pkgdep/debian.sh
new file mode 100644
index 0000000..3496e68
--- /dev/null
+++ b/util/pkgdep/debian.sh
@@ -0,0 +1,35 @@
+# -*- Mode:bash; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+#
+# Copyright (C) 2015-2021, The University of Memphis,
+#                          Arizona Board of Regents,
+#                          Regents of the University of California.
+#
+# This file is part of Mini-NDN.
+# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
+#
+# Mini-NDN is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mini-NDN is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mini-NDN, e.g., in COPYING.md file.
+# If not, see <http://www.gnu.org/licenses/>.
+
+if [[ $VERSION_ID -lt 11 ]]; then
+  cat <<EOT
+Debian 11 or newer is required
+Installation on older versions may fail
+EOT
+fi
+
+source "$PKGDEPDIR/debian-like.sh"
+
+APT_PKGS+=(
+  libigraph-dev
+)
diff --git a/util/pkgdep/fedora.sh b/util/pkgdep/fedora.sh
new file mode 100644
index 0000000..b48dac2
--- /dev/null
+++ b/util/pkgdep/fedora.sh
@@ -0,0 +1,57 @@
+# -*- Mode:bash; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+#
+# Copyright (C) 2015-2021, The University of Memphis,
+#                          Arizona Board of Regents,
+#                          Regents of the University of California.
+#
+# This file is part of Mini-NDN.
+# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
+#
+# Mini-NDN is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mini-NDN is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mini-NDN, e.g., in COPYING.md file.
+# If not, see <http://www.gnu.org/licenses/>.
+
+if [[ $VERSION_ID -lt 33 ]]; then
+  cat <<EOT
+Fedora 33 or newer is required
+Installation on older versions may fail
+EOT
+fi
+
+# DNF packages, written in alphabetical order.
+DNF_PKGS=(
+  boost-devel
+  ca-certificates
+  gcc-c++
+  libpcap-devel
+  openssl-devel
+  python3-pip
+  sqlite-devel
+  systemd-devel
+)
+
+install_pkgs() {
+  $SUDO dnf install -y "${DNF_PKGS[@]}"
+}
+
+prepare_ld() {
+  if ! $SUDO ldconfig -v 2>/dev/null | grep -q /usr/local/lib64; then 
+    echo 'Enabling /usr/local/lib64 in dynamic linker'
+    $SUDO mkdir -p /etc/ld.so.conf.d
+    echo /usr/local/lib64 | $SUDO tee /etc/ld.so.conf.d/usr-local-lib64.conf >/dev/null
+  fi
+}
+
+# ndn-cxx installs to /usr/local/lib64, but `pkg-config --libs libndn-cxx` by default strips out
+# `-L/usr/local/lib64` flag. This environ or `pkg-config --keep-system-libs` prevents that.
+export PKG_CONFIG_ALLOW_SYSTEM_LIBS=1
diff --git a/util/pkgdep/ubuntu.sh b/util/pkgdep/ubuntu.sh
new file mode 100644
index 0000000..91abc29
--- /dev/null
+++ b/util/pkgdep/ubuntu.sh
@@ -0,0 +1,37 @@
+# -*- Mode:bash; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+#
+# Copyright (C) 2015-2021, The University of Memphis,
+#                          Arizona Board of Regents,
+#                          Regents of the University of California.
+#
+# This file is part of Mini-NDN.
+# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
+#
+# Mini-NDN is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mini-NDN is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mini-NDN, e.g., in COPYING.md file.
+# If not, see <http://www.gnu.org/licenses/>.
+
+if [[ $(expr $VERSION_ID '<' 20.04) == 1 ]]; then
+  cat <<EOT
+Ubuntu 20.04 or newer is required
+Installation on older versions may fail
+EOT
+fi
+
+source "$PKGDEPDIR/debian-like.sh"
+
+APT_PKGS+=(
+  libigraph0-dev
+)
+
+PPA_AVAIL=1