From 922b7b673b86de263a7782c6963a6924b3c1d796 Mon Sep 17 00:00:00 2001 From: Rodny Molina Date: Wed, 25 Oct 2017 14:54:04 -0700 Subject: [PATCH] Exposing FRR's config to host FS and adjusting build-infra accordingly. [ PR not for merging purposes. My intention here is to simply answer the various questions that we have been getting from SONiC community concerning the approach we (Linkedin) follow to interact with FRR stack. Hope it helps. ] Functionally speaking, these are the changes being introduced in this patch: * FRR's config is now exposed to the host FS. * FRR is now relying on the unified-configuration model -- one single config file for all the FRR daemons -- frr.conf * FRR is now bypassing all minigraph.xml/config_db.json parsing logic, so FRR's docker entry-point logic is considerably simplified. * A new 'sonic' user is created to allow critical applications to operate with non-root privileges. * Corresponding 'uid-gid' is being exposed in rules/config to allow users to define their desired values. * FRR applications now run as 'sonic:sonic'. Signed-off-by: Rodny Molina --- build_debian.sh | 5 + dockers/docker-fpm-frr/Dockerfile.j2 | 6 +- dockers/docker-fpm-frr/config.sh | 21 - files/build_templates/docker_image_ctl.j2 | 3 + .../build_templates/sonic_debian_extension.j2 | 15 + rules/config | 12 + slave.mk | 9 + src/sonic-frr/Makefile | 23 +- src/sonic-frr/sonic_frr.init.d.frr | 575 ++++++++++++++++++ src/sonic-frr/sonic_frr.install | 1 - src/sonic-frr/sonic_frr.postinst | 33 + src/sonic-frr/sonic_frr.preinst | 61 ++ src/sonic-frr/sonic_frr.rules | 6 +- 13 files changed, 737 insertions(+), 33 deletions(-) delete mode 100755 dockers/docker-fpm-frr/config.sh mode change 100644 => 100755 files/build_templates/docker_image_ctl.j2 mode change 100644 => 100755 files/build_templates/sonic_debian_extension.j2 create mode 100755 src/sonic-frr/sonic_frr.init.d.frr create mode 100755 src/sonic-frr/sonic_frr.postinst create mode 100755 src/sonic-frr/sonic_frr.preinst diff --git a/build_debian.sh b/build_debian.sh index e893b9df403a..e14354d487b8 100755 --- a/build_debian.sh +++ b/build_debian.sh @@ -177,6 +177,11 @@ sudo LANG=C chroot $FILESYSTEM_ROOT useradd -G sudo,docker $USERNAME -c "$DEFAUL ## Create password for the default user echo "$USERNAME:$PASSWORD" | sudo LANG=C chroot $FILESYSTEM_ROOT chpasswd +## Create special 'sonic' user -- refer to rules/config for details. +sudo LANG=C chroot $FILESYSTEM_ROOT groupadd -g $SONIC_USER_GID sonic +sudo LANG=C chroot $FILESYSTEM_ROOT useradd -u $SONIC_USER_UID \ + -g $SONIC_USER_GID -M -s /bin/false sonic + ## Pre-install hardware drivers sudo LANG=C chroot $FILESYSTEM_ROOT apt-get -y install \ firmware-linux-nonfree diff --git a/dockers/docker-fpm-frr/Dockerfile.j2 b/dockers/docker-fpm-frr/Dockerfile.j2 index 194b91f33499..6d0b94136b8f 100644 --- a/dockers/docker-fpm-frr/Dockerfile.j2 +++ b/dockers/docker-fpm-frr/Dockerfile.j2 @@ -31,10 +31,8 @@ RUN apt-get autoremove -y RUN rm -rf /debs ~/.cache COPY ["*.j2", "/usr/share/sonic/templates/"] -COPY ["start.sh", "config.sh", "/usr/bin/"] +COPY ["start.sh", "/usr/bin/"] COPY ["daemons", "/etc/frr/"] COPY ["debian.conf", "/etc/frr/"] -ENTRYPOINT /usr/bin/config.sh \ - && /usr/bin/start.sh \ - && /bin/bash +ENTRYPOINT /usr/bin/start.sh && /bin/bash diff --git a/dockers/docker-fpm-frr/config.sh b/dockers/docker-fpm-frr/config.sh deleted file mode 100755 index ef7a13a214f4..000000000000 --- a/dockers/docker-fpm-frr/config.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -mkdir -p /etc/frr -sonic-cfggen -d -t /usr/share/sonic/templates/bgpd.conf.j2 >/etc/frr/bgpd.conf -sonic-cfggen -d -t /usr/share/sonic/templates/zebra.conf.j2 >/etc/frr/zebra.conf - -sonic-cfggen -d -t /usr/share/sonic/templates/isolate.j2 >/usr/sbin/bgp-isolate -chown root:root /usr/sbin/bgp-isolate -chmod 0755 /usr/sbin/bgp-isolate - -sonic-cfggen -d -t /usr/share/sonic/templates/unisolate.j2 >/usr/sbin/bgp-unisolate -chown root:root /usr/sbin/bgp-unisolate -chmod 0755 /usr/sbin/bgp-unisolate - -# If there's an integrated-config file, go ahead and remote it -if [ -f /etc/frr/frr.conf ]; then - rm -rf /etc/frr/frr.conf -fi - -mkdir -p /var/sonic -echo "# Config files managed by sonic-config-engine" >/var/sonic/config_status diff --git a/files/build_templates/docker_image_ctl.j2 b/files/build_templates/docker_image_ctl.j2 old mode 100644 new mode 100755 index 61f32f16b7b9..639cd1791900 --- a/files/build_templates/docker_image_ctl.j2 +++ b/files/build_templates/docker_image_ctl.j2 @@ -86,6 +86,9 @@ start() { -v /usr/share/sonic/device/$PLATFORM:/usr/share/sonic/platform:ro \ {%- if docker_container_name != "database" %} -v /usr/share/sonic/device/$PLATFORM/$HWSKU:/usr/share/sonic/hwsku:ro \ +{%- endif %} +{%- if docker_image_name == "docker-fpm-frr" %} + -v /etc/sonic/frr:/etc/frr:rw \ {%- endif %} --tmpfs /tmp \ --tmpfs /var/tmp \ diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 old mode 100644 new mode 100755 index 318c83f5f218..3140d2a9a133 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -319,3 +319,18 @@ sudo cp target/files/$MLNX_FW_FILE $FILESYSTEM_ROOT/etc/mlnx/fw-SPC.mfa j2 platform/mellanox/mlnx-fw-upgrade.j2 | sudo tee $FILESYSTEM_ROOT/usr/bin/mlnx-fw-upgrade.sh sudo chmod 755 $FILESYSTEM_ROOT/usr/bin/mlnx-fw-upgrade.sh {% endif %} + +## If FRR is elected as the routing-stack, its corresponding configuration file +## will be exposed to the host's file-system. With that goal in mind, here we are +## creating a dummy/empty config-file to serve as a placeholder for FRR's full +## configuration. +{%- if SONIC_ROUTING_STACK == "frr" %} +sudo mkdir $FILESYSTEM_ROOT/etc/sonic/frr +sudo touch $FILESYSTEM_ROOT/etc/sonic/frr/frr.conf +sudo touch $FILESYSTEM_ROOT/etc/sonic/frr/vtysh.conf +sudo cp dockers/docker-fpm-frr/debian.conf $FILESYSTEM_ROOT/etc/sonic/frr/ +sudo cp dockers/docker-fpm-frr/daemons $FILESYSTEM_ROOT/etc/sonic/frr/ +sudo chown -R $SONIC_USER_UID:$SONIC_USER_GID $FILESYSTEM_ROOT/etc/sonic/frr +sudo chmod 750 $FILESYSTEM_ROOT/etc/sonic/frr +sudo chmod -R 640 $FILESYSTEM_ROOT/etc/sonic/frr/ +{%- endif %} diff --git a/rules/config b/rules/config index 5e8a3389530d..bdb1fea4f2ea 100644 --- a/rules/config +++ b/rules/config @@ -71,3 +71,15 @@ ENABLE_ORGANIZATION_EXTENSIONS = y # build: build kernel from source # download: download pre-built kernel from Azure storage. DEFAULT_KERNEL_PROCURE_METHOD = build + +# SONIC_USER_UID/GID - A special user ('sonic') will be always created during +# image compilation. This special user will be in charged of running SONiC's +# critical applications, provided that these applications are willing to run +# with non-root privileges -- which should be encouraged. This user will have +# no login capabilities and will be created across all the execution contexts +# of the system: both docker containers and host. As we want this user to have +# the same privileges across all different contexts, we must rely on a unique +# 'uid:gid' pair to identify him in the system. In consequence, explicit +# uid:gid values must be provided at build time. +SONIC_USER_UID = 888 +SONIC_USER_GID = 888 diff --git a/slave.mk b/slave.mk index 4f1998680b29..ec0b13cc5d38 100644 --- a/slave.mk +++ b/slave.mk @@ -134,6 +134,15 @@ $(info "SONIC_PROFILING_ON" : "$(SONIC_PROFILING_ON)") $(info "KERNEL_PROCURE_METHOD" : "$(KERNEL_PROCURE_METHOD)") $(info ) +# Exporting ROUTING_STACK as an env-var to allow build-infra to conditionaly compile +# routing stack dependent components. +export SONIC_ROUTING_STACK + +# Exporting SONIC_USER_UID/GID values. +export SONIC_USER_UID +export SONIC_USER_GID + + ############################################################################### ## Generic rules section ## All rules must go after includes for propper targets expansion diff --git a/src/sonic-frr/Makefile b/src/sonic-frr/Makefile index b044781a60f2..807952537916 100644 --- a/src/sonic-frr/Makefile +++ b/src/sonic-frr/Makefile @@ -5,10 +5,25 @@ SHELL = /bin/bash MAIN_TARGET = frr_$(FRR_VERSION)_amd64.deb $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : - # Replacing frr's rules/install files with SONiC's own versions to activate - # specific knobs and adjust install process to address SONiC's needs. - cp sonic_frr.rules frr/debian/rules - cp sonic_frr.install frr/debian/frr.install + + # UID/GID env-vars must be explicitly passed to installation scripts to + # allow subsequent 'dpkg -i' process to make use of this variable. + if ! grep -q "^SONIC_USER_UID=" sonic_frr.preinst; then + sed -e"/^set -u/a SONIC_USER_GID=${SONIC_USER_GID}" \ + -e"/^set -u/a SONIC_USER_UID=${SONIC_USER_UID}" \ + sonic_frr.preinst > tmp_file && \ + mv tmp_file sonic_frr.preinst + fi + + pushd ./frr + + # Replacing frr's rules/install/service files with SONiC's own versions + # to activate specific knobs and adjust install process to SONiC needs. + cp ../sonic_frr.rules debian/rules + cp ../sonic_frr.install debian/frr.install + cp ../sonic_frr.preinst debian/frr.preinst + cp ../sonic_frr.postinst debian/frr.postinst + cp ../sonic_frr.init.d.frr tools/frr # Build the package pushd ./frr diff --git a/src/sonic-frr/sonic_frr.init.d.frr b/src/sonic-frr/sonic_frr.init.d.frr new file mode 100755 index 000000000000..29faec69a6c9 --- /dev/null +++ b/src/sonic-frr/sonic_frr.init.d.frr @@ -0,0 +1,575 @@ +#!/bin/bash +# +### BEGIN INIT INFO +# Provides: frr +# Required-Start: $local_fs $network $remote_fs $syslog +# Required-Stop: $local_fs $network $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: start and stop the Frr routing suite +# Description: Frr is a routing suite for IP routing protocols like +# BGP, OSPF, RIP and others. This script contols the main +# daemon "frr" as well as the individual protocol daemons. +### END INIT INFO +# + +PATH=/bin:/usr/bin:/sbin:/usr/sbin +D_PATH=/usr/lib/frr +C_PATH=/etc/frr +V_PATH=/var/run/frr + +# Local Daemon selection may be done by using /etc/frr/daemons. +# See /usr/share/doc/frr/README.Debian.gz for further information. +# Keep zebra first and do not list watchfrr! +DAEMONS="zebra bgpd" +MAX_INSTANCES=5 +RELOAD_SCRIPT=/usr/lib/frr/frr-reload.py + +. /lib/lsb/init-functions + +if [ -f /usr/lib/frr/ssd ]; then + SSD=/usr/lib/frr/ssd +else + SSD=`which start-stop-daemon` +fi + +# Print the name of the pidfile. +pidfile() +{ + echo "$V_PATH/$1.pid" +} + +# Print the name of the vtysh. +vtyfile() +{ + echo "$V_PATH/$1.vty" +} + +# Check if daemon is started by using the pidfile. +started() +{ + [ ! -e `pidfile $1` ] && return 3 + if [ -n "$2" ] && [ "$2" == "log" ]; then + status_of_proc -p `pidfile $1` $1 $1 && return 0 || return $? + else + kill -0 `cat \`pidfile $1\`` 2> /dev/null || return 1 + return 0 + fi +} + +# Loads the config via vtysh -b if configured to do so. +vtysh_b () +{ + # Rember, that all variables have been incremented by 1 in convert_daemon_prios() + if [ "$vtysh_enable" = 2 -a -f $C_PATH/frr.conf ]; then + /usr/bin/vtysh -b -n + fi +} + +# Check if the daemon is activated and if its executable and config files +# are in place. +# params: daemon name +# returns: 0=ok, 1=error +check_daemon() +{ + # If the integrated config file is used the others are not checked. + if [ -r "$C_PATH/frr.conf" ]; then + return 0 + fi + + # vtysh_enable has no config file nor binary so skip check. + # (Not sure why vtysh_enable is in this list but does not hurt) + if [ $1 != "watchfrr" -a $1 != "vtysh_enable" ]; then + # check for daemon binary + if [ ! -x "$D_PATH/$1" ]; then return 1; fi + + # check for config file + if [ -n "$2" ]; then + if [ ! -r "$C_PATH/$1-$2.conf" ]; then + touch "$C_PATH/$1-$2.conf" + chown sonic:sonic "$C_PATH/$1-$2.conf" + fi + elif [ ! -r "$C_PATH/$1.conf" ]; then + touch "$C_PATH/$1.conf" + chown sonic:sonic "$C_PATH/$1.conf" + fi + fi + return 0 +} + +# Starts the server if it's not alrady running according to the pid file. +# The Frr daemons creates the pidfile when starting. +start() +{ + ulimit -n $MAX_FDS + if [ "$1" = "watchfrr" ]; then + + # We may need to restart watchfrr if new daemons are added and/or + # removed + if started "$1" ; then + stop watchfrr + else + # Echo only once. watchfrr is printed in the stop above + echo -n " $1" + fi + + if [ -e /var/run/frr/watchfrr.started ] ; then + rm /var/run/frr/watchfrr.started + fi + ${SSD} \ + --start \ + --pidfile=`pidfile $1` \ + --exec "$D_PATH/$1" \ + -- \ + "${watchfrr_options[@]}" + for i in `seq 1 10`; + do + if [ -e /var/run/frr/watchfrr.started ] ; then + break + else + sleep 1 + fi + done + elif [ -n "$2" ]; then + echo -n " $1-$2" + if ! check_daemon $1 $2 ; then + echo -n " (binary does not exist)" + return; + fi + + ${SSD} \ + --start \ + --pidfile=`pidfile $1-$2` \ + --exec "$D_PATH/$1" \ + -- \ + `eval echo "$""$1""_options"` -n "$2" + else + echo -n " $1" + if ! check_daemon $1; then + echo -n " (binary does not exist)" + return; + fi + + ${SSD} \ + --start \ + --pidfile=`pidfile $1` \ + --exec "$D_PATH/$1" \ + -- \ + `eval echo "$""$1""_options"` + fi +} + +# Stop the daemon given in the parameter, printing its name to the terminal. +stop() +{ + local inst + + if [ -n "$2" ]; then + inst="$1-$2" + else + inst="$1" + fi + + if ! started "$inst" ; then + echo -n " ($inst)" + return 0 + else + PIDFILE=`pidfile $inst` + PID=`cat $PIDFILE 2>/dev/null` + ${SSD} --stop --quiet --retry=TERM/30/KILL/5 --oknodo --pidfile "$PIDFILE" --exec "$D_PATH/$1" + # + # Now we have to wait until $DAEMON has _really_ stopped. + # + if test -n "$PID" && kill -0 $PID 2>/dev/null; then + echo -n " (waiting) ." + cnt=0 + while kill -0 $PID 2>/dev/null; do + cnt=`expr $cnt + 1` + if [ $cnt -gt 60 ]; then + # Waited 120 secs now, fail. + echo -n "Failed.. " + break + fi + sleep 2 + echo -n "." + done + fi + echo -n " $inst" + rm -f `pidfile $inst` + rm -f `vtyfile $inst` + fi +} + +# Converts values from /etc/frr/daemons to all-numeric values. +convert_daemon_prios() +{ + for name in $DAEMONS zebra vtysh_enable watchfrr_enable; do + # First, assign the value set by the user to $value + eval value=\${${name}:0:3} + + # Daemon not activated or entry missing? + if [ "$value" = "no" -o "$value" = "" ]; then value=0; fi + + # These strings parsed for backwards compatibility. + if [ "$value" = "yes" -o "$value" = "true" ]; then + value=1; + fi + + # Zebra is threatened special. It must be between 0=off and the first + # user assigned value "1" so we increase all other enabled daemons' values. + if [ "$name" != "zebra" -a "$value" -gt 0 ]; then value=`expr "$value" + 1`; fi + + # If e.g. name is zebra then we set "zebra=yes". + eval $name=$value + done +} + +# Starts watchfrr for all wanted daemons. +start_watchfrr() +{ + local daemon_name + local daemon_prio + local found_one + local daemon_inst + + # Start the monitor daemon only if desired. + if [ 0 -eq "$watchfrr_enable" ]; then + return + fi + + # Check variable type + if ! declare -p watchfrr_options | grep -q '^declare \-a'; then + echo + echo "ERROR: The variable watchfrr_options from /etc/frr/debian.cnf must be a BASH array!" + echo "ERROR: Please convert config file and restart!" + exit 1 + fi + + # Which daemons have been started? + found_one=0 + for daemon_name in $DAEMONS; do + eval daemon_prio=\$$daemon_name + if [ "$daemon_prio" -gt 0 ]; then + eval "daemon_inst=\${${daemon_name}_instances//,/ }" + if [ -n "$daemon_inst" ]; then + for inst in ${daemon_inst}; do + eval "inst_disable=\${${daemon_name}_${inst}}" + if [ -z ${inst_disable} ] || [ ${inst_disable} != 0 ]; then + if check_daemon $daemon_name $inst; then + watchfrr_options+=("${daemon_name}-${inst}") + fi + fi + done + else + if check_daemon $daemon_name; then + watchfrr_options+=($daemon_name) + fi + fi + found_one=1 + fi + done + + # Start if at least one daemon is activated. + if [ $found_one -eq 1 ]; then + echo -n "Starting Frr monitor daemon:" + start watchfrr + echo "." + fi +} + +# Stopps watchfrr. +stop_watchfrr() +{ + echo -n "Stopping Frr monitor daemon:" + stop watchfrr + echo "." +} + +# Stops all daemons that have a lower level of priority than the given. +# (technically if daemon_prio >= wanted_prio) +stop_prio() +{ + local wanted_prio + local daemon_prio + local daemon_list + local daemon_inst + local inst + + if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then + daemon=${BASH_REMATCH[1]} + inst=${BASH_REMATCH[2]} + else + daemon="$2" + fi + + wanted_prio=$1 + daemon_list=${daemon:-$DAEMONS} + + echo -n "Stopping Frr daemons (prio:$wanted_prio):" + + for prio_i in `seq 10 -1 $wanted_prio`; do + for daemon_name in $daemon_list; do + eval daemon_prio=\${${daemon_name}:0:3} + daemon_inst="" + if [ $daemon_prio -eq $prio_i ]; then + eval "daemon_inst=\${${daemon_name}_instances//,/ }" + if [ -n "$daemon_inst" ]; then + for i in ${daemon_inst}; do + if [ -n "$inst" ] && [ "$i" == "$inst" ]; then + stop "$daemon_name" "$inst" + elif [ x"$inst" == x ]; then + stop "$daemon_name" "$i" + fi + done + else + stop "$daemon_name" + fi + fi + done + done + + echo "." + if [ -z "$inst" ]; then + # Now stop other daemons that're prowling, coz the daemons file changed + echo -n "Stopping other frr daemons" + if [ -n "$daemon" ]; then + eval "file_list_suffix="$V_PATH"/"$daemon*"" + else + eval "file_list_suffix="$V_PATH/*"" + fi + for pidfile in $file_list_suffix.pid; do + PID=`cat $pidfile 2>/dev/null` + ${SSD} --stop --quiet --oknodo --pidfile "$pidfile" + echo -n "." + rm -rf "$pidfile" + done + echo "." + + echo -n "Removing remaining .vty files" + for vtyfile in $file_list_suffix.vty; do + rm -rf "$vtyfile" + done + echo "." + fi +} + +# Starts all daemons that have a higher level of priority than the given. +# (technically if daemon_prio <= wanted_prio) +start_prio() +{ + local wanted_prio + local daemon_prio + local daemon_list + local daemon_name + local daemon_inst + local inst + + if [ -n "$2" ] && [[ "$2" =~ (.*)-(.*) ]]; then + daemon=${BASH_REMATCH[1]} + inst=${BASH_REMATCH[2]} + else + daemon="$2" + fi + + wanted_prio=$1 + daemon_list=${daemon:-$DAEMONS} + + echo -n "Starting Frr daemons (prio:$wanted_prio):" + + for prio_i in `seq 1 $wanted_prio`; do + for daemon_name in $daemon_list; do + eval daemon_prio=\$${daemon_name} + daemon_inst="" + if [ $daemon_prio -eq $prio_i ]; then + eval "daemon_inst=\${${daemon_name}_instances//,/ }" + if [ -n "$daemon_inst" ]; then + if [ `echo "$daemon_inst" | wc -w` -gt ${MAX_INSTANCES} ]; then + echo "Max instances supported is ${MAX_INSTANCES}. Aborting" + exit 1 + fi + # Check if we're starting again by switching from single instance + # to MI version + if started "$daemon_name"; then + PIDFILE=`pidfile $daemon_name` + ${SSD} \ + --stop --quiet --oknodo \ + --pidfile "$PIDFILE" \ + --exec "$D_PATH/$daemon_name" + + rm -f `pidfile $1` + rm -f `vtyfile $1` + fi + + for i in ${daemon_inst}; do + if [ -n "$inst" ] && [ "$i" == "$inst" ]; then + start "$daemon_name" "$inst" + elif [ x"$inst" == x ]; then + start "$daemon_name" "$i" + fi + done + else + # Check if we're starting again by switching from + # single instance to MI version + eval "file_list_suffix="$V_PATH"/"$daemon_name-*"" + for pidfile in $file_list_suffix.pid; do + ${SSD} --stop --quiet --oknodo --pidfile "$pidfile" + echo -n "." + rm -rf "$pidfile" + done + for vtyfile in $file_list_suffix.vty; do + rm -rf "$vtyfile" + done + + start "$daemon_name" + fi + fi + done + done + echo "." +} + +check_status() +{ + local daemon_name + local daemon_prio + local daemon_inst + local failed_status=0 + + if [ -n "$1" ] && [[ "$1" =~ (.*)-(.*) ]]; then + daemon=${BASH_REMATCH[1]} + inst=${BASH_REMATCH[2]} + else + daemon="$1" + fi + + daemon_list=${daemon:-$DAEMONS} + + # Which daemons have been started? + for daemon_name in $daemon_list; do + eval daemon_prio=\$$daemon_name + if [ "$daemon_prio" -gt 0 ]; then + eval "daemon_inst=\${${daemon_name}_instances//,/ }" + if [ -n "$daemon_inst" ]; then + for i in ${daemon_inst}; do + if [ -n "$inst" -a "$inst" = "$i" ]; then + started "$1" "log" || failed_status=$? + elif [ -z "$inst" ]; then + started "$daemon_name-$i" "log" || failed_status=$? + fi + done + else + started "$daemon_name" "log" || failed_status=$? + fi + fi + done + + # All daemons that need to have been started are up and running + return $failed_status +} + +######################################################### +# Main program # +######################################################### + +# Config broken but script must exit silently. +[ ! -r "$C_PATH/daemons" ] && exit 0 + +# Load configuration +. "$C_PATH/daemons" +. "$C_PATH/debian.conf" + +# Read configuration variable file if it is present +[ -r /etc/default/frr ] && . /etc/default/frr + +MAX_INSTANCES=${MAX_INSTANCES:=5} + +# Set priority of un-startable daemons to 'no' and substitute 'yes' to '0' +convert_daemon_prios + +if [ ! -d $V_PATH ]; then + echo "Creating $V_PATH" + mkdir -p $V_PATH + chown sonic:sonic $V_PATH + chmod 755 /$V_PATH +fi + +if [ -n "$3" ] && [ "$3" != "all" ]; then + dmn="$2"-"$3" +elif [ -n "$2" ] && [ "$2" != "all" ]; then + dmn="$2" +fi + +case "$1" in + start) + # Try to load this necessary (at least for 2.6) module. + if [ -d /lib/modules/`uname -r` ] ; then + echo "Loading capability module if not yet done." + set +e; LC_ALL=C modprobe -a capability 2>&1 | egrep -v "(not found|Can't locate)"; set -e + fi + + # Start all daemons + cd $C_PATH/ + if [ "$2" != "watchfrr" ]; then + start_prio 10 $dmn + fi + start_watchfrr + vtysh_b + ;; + + 1|2|3|4|5|6|7|8|9|10) + # Stop/start daemons for the appropriate priority level + stop_prio $1 + start_prio $1 + vtysh_b + ;; + + stop|0) + # Stop all daemons at level '0' or 'stop' + stop_watchfrr + if [ "$dmn" != "watchfrr" ]; then + [ -n "${dmn}" ] && eval "${dmn/-/_}=0" + stop_prio 0 $dmn + fi + + if [ -z "$dmn" -o "$dmn" = "zebra" ]; then + echo "Removing all routes made by zebra." + ip route flush proto zebra + else + [ -n "$dmn" ] && eval "${dmn/-/_}=0" + start_watchfrr + fi + ;; + + reload) + # Just apply the commands that have changed, no restart necessary + [ ! -x "$RELOAD_SCRIPT" ] && echo "frr-reload script not available" && exit 0 + NEW_CONFIG_FILE="${2:-$C_PATH/frr.conf}" + [ ! -r $NEW_CONFIG_FILE ] && echo "Unable to read new configuration file $NEW_CONFIG_FILE" && exit 1 + echo "Applying only incremental changes to running configuration from frr.conf" + "$RELOAD_SCRIPT" --reload /etc/frr/frr.conf + exit $? + ;; + + status) + check_status $dmn + exit $? + ;; + + restart|force-reload) + $0 stop $dmn + sleep 1 + $0 start $dmn + ;; + + *) + echo "Usage: /etc/init.d/frr {start|stop|status|reload|restart|force-reload|} [daemon]" + echo " E.g. '/etc/init.d/frr 5' would start all daemons with a prio 1-5." + echo " reload applies only modifications from the running config to all daemons." + echo " reload neither restarts starts any daemon nor starts any new ones." + echo " Read /usr/share/doc/frr/README.Debian for details." + exit 1 + ;; +esac + +echo "Exiting from the script" +exit 0 diff --git a/src/sonic-frr/sonic_frr.install b/src/sonic-frr/sonic_frr.install index b0bf8d6909a7..fa54779a60df 100644 --- a/src/sonic-frr/sonic_frr.install +++ b/src/sonic-frr/sonic_frr.install @@ -18,6 +18,5 @@ usr/share/man/man8/zebra.8 usr/share/man/man8/isisd.8 usr/share/man/man8/watchfrr.8 usr/share/snmp/mibs/ -cumulus/etc/* etc/ tools/*.service lib/systemd/system debian/frr.conf usr/lib/tmpfiles.d diff --git a/src/sonic-frr/sonic_frr.postinst b/src/sonic-frr/sonic_frr.postinst new file mode 100755 index 000000000000..995c5786920d --- /dev/null +++ b/src/sonic-frr/sonic_frr.postinst @@ -0,0 +1,33 @@ +#!/bin/bash -e + +# Adjusting FRR's file-system permissions to allow 'sonic' user to own +# the FRR's execution environment. + +chown -R sonic:sonic /etc/frr +touch /etc/frr/vtysh.conf +chgrp sonic /etc/frr/vtysh* +chmod 640 /etc/frr/* +chown -R sonic:sonic /var/run/frr +chown -R sonic:sonic /var/log/frr + + +ENVIRONMENTFILE=/etc/environment +if ! grep --quiet VTYSH_PAGER=/bin/cat ${ENVIRONMENTFILE}; then + echo "VTYSH_PAGER=/bin/cat" >> ${ENVIRONMENTFILE} +fi + +if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi +${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*"} + +# This is most likely due to the answer "no" to the "really stop the server" +# question in the prerm script. +if [ "$1" = "abort-upgrade" ]; then + exit 0 +fi + +. /usr/share/debconf/confmodule + +db_stop + +#DEBHELPER# + diff --git a/src/sonic-frr/sonic_frr.preinst b/src/sonic-frr/sonic_frr.preinst new file mode 100755 index 000000000000..092e3c2989de --- /dev/null +++ b/src/sonic-frr/sonic_frr.preinst @@ -0,0 +1,61 @@ +#!/bin/bash + +if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi +${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*"} +set -e +set -u + +# creating sonic group if it isn't already there +if ! getent group sonic > /dev/null; then + groupadd -g $SONIC_USER_GID sonic > /dev/null +fi + +# creating sonic user if isn't already there +if ! getent passwd sonic >/dev/null; then + useradd -u $SONIC_USER_UID -g $SONIC_USER_GID \ + --shell /bin/false sonic > /dev/null +fi + +# Do not change permissions when upgrading as it would violate policy. +if [ "$1" = "install" ]; then + # Logfiles are group readable in case users were put into the sonic group. + d=/var/log/frr/ + mkdir -p $d + chown -R sonic:sonic $d + chmod u=rw,g=r,o= $d + find $d -type f -print0 | xargs -0 --no-run-if-empty chmod u=rw,g=r,o= + + # Strict permissions for the sockets. + d=/var/run/frr/ + mkdir -p $d + chown -R sonic:sonic $d + chmod u=rwx,go=rx $d + find $d -type f -print0 | xargs -0 --no-run-if-empty chmod u=rw,go= + + # Config files. Vtysh does not have access to the individual daemons config file + d=/etc/frr/ + mkdir -p $d + chown sonic:sonic $d + chmod u=rwx,g=r,o= $d + find $d -type f -print0 | xargs -0 --no-run-if-empty chown sonic:sonic + find $d -type f -print0 | xargs -0 --no-run-if-empty chmod u=rw,g=r,o= + + # Exceptions for vtysh. + f=$d/vtysh.conf + if [ -f $f ]; then + chown sonic:sonic $f + chmod u=rw,g=r,o= $f + fi + + # Exceptions for vtysh. + f=$d/frr.conf + if [ -f $d/Zebra.conf ]; then + mv $d/Zebra.conf $f + fi + if [ -f $f ]; then + chown sonic:sonic $f + chmod u=rw,g=r,o= $f + fi +fi + +#DEBHELPER# diff --git a/src/sonic-frr/sonic_frr.rules b/src/sonic-frr/sonic_frr.rules index f4e0706b5c33..330a0454da92 100755 --- a/src/sonic-frr/sonic_frr.rules +++ b/src/sonic-frr/sonic_frr.rules @@ -41,9 +41,9 @@ override_dh_auto_configure: --enable-vtysh=yes \ --enable-isisd=yes \ --enable-multipath=256 \ - --enable-user=frr \ - --enable-group=frr \ - --enable-vty-group=frrvty \ + --enable-user=sonic \ + --enable-group=sonic \ + --enable-vty-group=sonic \ --enable-configfile-mask=0640 \ --enable-logfile-mask=0640 \ --enable-werror \