#!/bin/bash # # Resource script for vrouter namespace support # # Description: Manages vrouter namespace as an OCF resource in # an High Availability setup # # Vrouter OCF script's Author: Mirantis # License: GNU General Public License (GPL) # # usage: $0 {start|stop|restart|status|monitor|validate-all|meta-data} # # The "start" arg starts vrouter. # # The "stop" arg stops it. # # OCF parameters: # OCF_RESKEY_ns # OCF_RESKEY_other_networks # # OCF_RESKEY_host_interface # OCF_RESKEY_namespace_interface # OCF_RESKEY_host_ip # OCF_RESKEY_namespace_ip # OCF_RESKEY_network_mask # OCF_RESKEY_route_metric # ########################################################################## # Initialization: OCF_ROOT_default="/usr/lib/ocf" OCF_RESKEY_ns_default="vrouter" OCF_RESKEY_other_networks_default=false OCF_RESKEY_host_interface_default="vr-host-base" OCF_RESKEY_namespace_interface_default="vr-host-ns" OCF_RESKEY_host_ip_default="240.0.0.5" OCF_RESKEY_namespace_ip_default="240.0.0.6" OCF_RESKEY_network_mask_default="30" OCF_RESKEY_route_metric_default="10000" : ${OCF_ROOT=${OCF_ROOT_default}} : ${HA_LOGTAG="ocf-ns_vrouter"} : ${HA_LOGFACILITY="daemon"} : ${OCF_RESKEY_ns=${OCF_RESKEY_ns_default}} : ${OCF_RESKEY_other_networks=${OCF_RESKEY_other_networks_default}} : ${OCF_RESKEY_host_interface=${OCF_RESKEY_host_interface_default}} : ${OCF_RESKEY_namespace_interface=${OCF_RESKEY_namespace_interface_default}} : ${OCF_RESKEY_host_ip=${OCF_RESKEY_host_ip_default}} : ${OCF_RESKEY_namespace_ip=${OCF_RESKEY_namespace_ip_default}} : ${OCF_RESKEY_network_mask=${OCF_RESKEY_network_mask_default}} : ${OCF_RESKEY_route_metric=${OCF_RESKEY_route_metric_default}} : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/heartbeat} . ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs USAGE="Usage: $0 {start|stop|restart|status|monitor|validate-all|meta-data}"; RUN_IN_NS="ip netns exec $OCF_RESKEY_ns " if [[ -z $OCF_RESKEY_ns ]] ; then RUN='' else RUN="$RUN_IN_NS " fi ########################################################################## usage() { echo $USAGE >&2 } meta_data() { cat < 1.0 This script manages vrouter daemon with namespace support Manages an vrouter daemon inside an namespace Name of network namespace. Should be present. Name of network namespace. Additional routes that should be added to this resource. Routes will be added via value namespace_interface. List of addtional routes to add routes for. The host part of the interface pair used to connect the namespace to the network For example, "vrouter-host" The name of the host interface used for namespace The namespace part of the interface pair used to connect the namespace to the network For example, "vr-ns" The name of the namespace interface used for namespace The IP address used by the host interface. Must be from the same subnet as namesapce IP and uses network_mask to determine subnet. Should not collide with any IP addresses already used in your network. For example, "240.0.0.5" Host interface IP address The IP address used by the namespace interface. Must be from the same subnet as host IP and uses network_mask to determine subnet. Should not collide with any IP addresses already used in your network. For example, "240.0.0.6" Namespace interface IP address The network mask length used to determine subnet of the host and the namspace interfaces. For example, "30" Network mask length The metric value of the default route set for the pipe link connecting namespace and host. It should be set to a large number to be higher then other default route metrics that could be set to override this default route. If other routes are set eithin the namespace thir metric should be smaller then this number if you want them to be used istead of this route. For example, "1000" Namespace default route metric END exit $OCF_SUCCESS } nsip() { ip netns exec "${OCF_RESKEY_ns}" ip ${@} } check_ns() { local LH="${LL} check_ns():" local ns=$(ip netns list | awk "/${OCF_RESKEY_ns}/ {print \$1}") ocf_log debug "${LH} recieved netns list: ${ns}" [[ "$ns" != $OCF_RESKEY_ns ]] && return $OCF_ERR_GENERIC ocf_run $RUN_IN_NS sysctl -w net.ipv4.ip_forward=1 return $OCF_SUCCESS } get_ns() { local rc local LH="${LL} get_ns():" check_ns && return $OCF_SUCCESS ocf_run ip netns add $OCF_RESKEY_ns rc=$? ocf_run $RUN_IN_NS /sbin/sysctl -w net.ipv4.ip_nonlocal_bind=1 ocf_run $RUN_IN_NS sysctl -w net.ipv4.ip_forward=1 ocf_run $RUN_IN_NS ip link set up dev lo ocf_log debug "${LH} added netns ${OCF_RESKEY_ns} and set up lo" return $rc } set_ns_interfaces() { # create host-ns veth pair unless it's present ip link | grep -q '^[[:digit:]]\+:[[:space:]]\+'"${OCF_RESKEY_host_interface}"'[@:]' if [ $? -gt 0 ]; then ocf_log debug "Creating host interface: ${OCF_RESKEY_host_interface} and namespace interface: ${OCF_RESKEY_namespace_interface}" ocf_run ip link add "${OCF_RESKEY_host_interface}" type veth peer name "${OCF_RESKEY_namespace_interface}" else return $OCF_SUCCESS fi # move the ns part to the namespace ip link | grep -q '^[[:digit:]]\+:[[:space:]]\+'"${OCF_RESKEY_namespace_interface}"'[@:]' if [ $? -eq 0 ]; then ocf_log debug "Moving interface: ${OCF_RESKEY_namespace_interface} to namespace: ${OCF_RESKEY_ns}" ocf_run ip link set dev "${OCF_RESKEY_namespace_interface}" netns "${OCF_RESKEY_ns}" fi # up the host part ocf_log debug "Bringing up host interface: ${OCF_RESKEY_host_interface}" ocf_run ip link set "${OCF_RESKEY_host_interface}" up # set host part's ip ip addr show dev "${OCF_RESKEY_host_interface}" | grep -q "inet ${OCF_RESKEY_host_ip}/${OCF_RESKEY_network_mask}" if [ $? -gt 0 ]; then ocf_log debug "Setting host interface: ${OCF_RESKEY_host_interface} IP to: ${OCF_RESKEY_host_ip}/${OCF_RESKEY_network_mask}" ocf_run ip addr add "${OCF_RESKEY_host_ip}/${OCF_RESKEY_network_mask}" dev "${OCF_RESKEY_host_interface}" fi # up the ns part ocf_log debug "Bringing up the namespace interface: ${OCF_RESKEY_namespace_interface}" ocf_run nsip link set "${OCF_RESKEY_namespace_interface}" up # set ns part's ip nsip addr show dev "${OCF_RESKEY_namespace_interface}" | grep -q "inet ${OCF_RESKEY_namespace_ip}/${OCF_RESKEY_network_mask}" if [ $? -gt 0 ]; then ocf_log debug "Setting namespace interface: ${OCF_RESKEY_namespace_interface} IP to: ${OCF_RESKEY_namespace_ip}/${OCF_RESKEY_network_mask}" ocf_run nsip addr add "${OCF_RESKEY_namespace_ip}/${OCF_RESKEY_network_mask}" dev "${OCF_RESKEY_namespace_interface}" fi } set_ns_routing() { # set default gateway inside ns nsip route list | grep -q "default via ${OCF_RESKEY_host_ip}" if [ $? -gt 0 ]; then ocf_log debug "Creating default route inside the namespace to ${OCF_RESKEY_host_ip} with metric ${OCF_RESKEY_route_metric}" ocf_run nsip route add default via "${OCF_RESKEY_host_ip}" metric "${OCF_RESKEY_route_metric}" fi # set masquerade on host node iptables -n --wait -t nat -L | grep -q masquerade-for-vrouter-namespace if [ $? -gt 0 ]; then ocf_log debug "Creating NAT rule on the host system for traffic from IP: ${OCF_RESKEY_namespace_ip}" ocf_run iptables --wait -t nat -A POSTROUTING -s "${OCF_RESKEY_namespace_ip}" -j MASQUERADE -m comment --comment "masquerade-for-vrouter-namespace" fi ### Needed for ML2 routing ### ocf_run sysctl -w net.ipv4.conf.${OCF_RESKEY_host_interface}.rp_filter=2 ocf_run $RUN_IN_NS sysctl -w net.ipv4.conf.all.rp_filter=2 ############################## if [[ "${OCF_RESKEY_other_networks}" != "false" ]] ; then for network in ${OCF_RESKEY_other_networks} do ocf_log debug "Adding route on the host system to ${network}: ${OCF_RESKEY_namespace_ip}" ocf_run $RUN_IN_NS ip route replace ${network} via ${OCF_RESKEY_host_ip} metric 10000 done fi } set_ns_flushing() { ocf_log debug "Flushing global scope routes" nsip route save '0.0.0.0/0' > ${HA_RSCTMP}/default.routes nsip route flush scope global nsip route restore < ${HA_RSCTMP}/default.routes } vrouter_status() { get_ns || return $OCF_NOT_RUNNING set_ns_interfaces set_ns_routing } vrouter_start() { get_ns set_ns_interfaces set_ns_flushing set_ns_routing return $OCF_SUCCESS } vrouter_stop() { ocf_log debug "Vrouter was stopped, namespaces still exist" return $OCF_SUCCESS } vrouter_monitor() { vrouter_status } vrouter_validate_all() { get_ns return $OCF_SUCCESS } vrouter_restart() { vrouter_stop vrouter_start } # # Main # if [ $# -ne 1 ]; then usage exit $OCF_ERR_ARGS fi umask 0022 export LL="${OCF_RESOURCE_INSTANCE}:" case $1 in start) vrouter_start ;; stop) vrouter_stop ;; restart) vrouter_restart ;; status) vrouter_status ;; monitor) vrouter_monitor ;; validate-all) vrouter_validate_all ;; meta-data) meta_data ;; usage) usage; exit $OCF_SUCCESS ;; *) usage; exit $OCF_ERR_UNIMPLEMENTED ;; esac