├── LICENSE ├── README ├── README.md ├── agent ├── README ├── bandwidth │ ├── create_ovs_queues.ksh │ ├── map_mac2phost.ksh │ ├── ovs_sp2uuid.ksh │ ├── purge_ovs_queues.ksh │ ├── ql_bw_fmods.ksh │ ├── ql_bwow_fmods.ksh │ ├── ql_filter_rtr.ksh │ ├── ql_pass_fmods.ksh │ ├── ql_set_trunks.ksh │ ├── ql_setup_ipt.ksh │ ├── ql_setup_irl.ksh │ ├── ql_suss_queues.ksh │ ├── send_ovs_fmod.ksh │ └── setup_ovs_intermed.ksh └── mirror │ ├── tegu_add_mirror.ksh │ └── tegu_del_mirror.ksh ├── const.go ├── doc ├── rjprt.1 ├── tegu.8 ├── tegu.cfg.5 └── tegu_req.1 ├── gizmos ├── fence.go ├── flight_if.go ├── flowmod.go ├── gate.go ├── gizmos_lite_test.go ├── gizmos_net_test.go ├── gizmos_pt_test.go ├── gizmos_test.go ├── gizmos_tools_test.go ├── host.go ├── init.go ├── link.go ├── lite.go ├── mbox.go ├── mlag.go ├── obligation.go ├── path.go ├── pledge.go ├── pledge_base.go ├── pledge_bw.go ├── pledge_bwow.go ├── pledge_mirror.go ├── pledge_pass.go ├── pledge_steer.go ├── pledge_test.go ├── pledge_window.go ├── queue.go ├── spq.go ├── switch.go ├── time_slice.go └── tools.go ├── main ├── rjprt.go ├── tegu.go ├── tegu_agent.go └── tegu_template.cfg ├── managers ├── agent.go ├── fq_mgr.go ├── fq_mgr_steer.go ├── fq_pass.go ├── fq_req.go ├── globals.go ├── http_api.go ├── http_fetch.go ├── http_mirror_api.go ├── mgr_tools.go ├── net_req.go ├── network.go ├── network_path.go ├── osif.go ├── osif_proj.go ├── res_mgr.go ├── res_mgr_bw.go ├── res_mgr_mirror.go ├── res_mgr_pt.go ├── res_mgr_steer.go ├── rm_recovery.go └── xmanagers_test.go ├── support └── tegu_verification.ksh └── system ├── crontab.qlite ├── ql_snuff.ksh ├── start_tegu_agent.ksh ├── start_tegu_ha.ksh ├── start_tegu_qlite.ksh ├── tegu_ha.py ├── tegu_rc.ksh ├── tegu_req.ksh ├── tegu_standby.ksh ├── tegu_synch.ksh └── toponet.py /LICENSE: -------------------------------------------------------------------------------- 1 | This licence applies to all files in this repository unless otherwise specifically 2 | stated inside of the file. 3 | 4 | --------------------------------------------------------------------------- 5 | Copyright (c) 2013-2015 AT&T Intellectual Property 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at: 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | --------------------------------------------------------------------------- 19 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | Tegu is a reservation manager which provides the ability to create and manage: 3 | - quality of service bandwidth reservations 4 | - flow steering reservations 5 | - wide area network stitching 6 | 7 | Tegu uses an underlying agent, also included in this repo, to directly manage the 8 | physical components (OVS or switches) as is needed to implement the reservations. 9 | The underlying agent scripts are contained in the agent directory and the agent 10 | binary is in the main directory. 11 | 12 | The tegu src is divided into two packages and the main: 13 | agent -- Directories containing various direct interfaces to things like 14 | OVS, Arista switches, floodlight (skoogie), mirroring, etc. 15 | 16 | managers -- functions that are driven as goroutines and thus implement 17 | major components of the application (reservation manager, 18 | fq manager, etc.). 19 | 20 | gizmos -- source files which implement objects, interfaces and the 21 | functions that operate directly on them (link, host, switch, 22 | pledge, etc.). 23 | 24 | main -- Entry point functions (tegu and tegu_agent) 25 | 26 | package -- Scripts and metadata templates used to build a package files (.deb) 27 | 28 | system -- Scripts used to start/stop/manage tegu in a q-lite environment. 29 | 30 | 31 | Gizmos: 32 | globals.go constants and a few globals shared by *.go in this directory 33 | This module also contains the initialisation function that 34 | sets all globals up. 35 | 36 | flight_if.go floodlight interface providing methods that allow queries to the 37 | controller for gathering link and host information. 38 | 39 | fence.go Implements a user limit fence mechanism. 40 | 41 | host.go represents a single host in the network graph and in a path 42 | 43 | init.go package level initialisation. 44 | 45 | light.go functions that were implemented quickly to support tegu-lite. These 46 | probably should be moved to separate files, or likely into tools, but 47 | during the hasty implementation of -lite it was easier to keep them 48 | bunched here. 49 | 50 | link.go represents a link between switches in the network graph and in a path 51 | 52 | mbox.go middlebox representation for steering reserations. 53 | 54 | obligation.go used to manage an obligation of something over time; references may time slices 55 | 56 | path.go manages a path that has been created with a given amout of bandwith 57 | 58 | pledge.go an interface representing a reservation tracked by resmgr. Implemented 59 | by pledge_* structs in the pledge_* files. 60 | pledge_bw.go 61 | pledge_mirror.go 62 | pledge_steer.go 63 | 64 | pledge_window.go Manages a time window for pledges and provides basic is_active, is_expired 65 | functions. 66 | 67 | queue.go manages information needed to set individual queues for a reservation 68 | 69 | spq.go a very simple object which allows the return of queue information to a caller in 70 | a single bundle (presently, just the struct, no functions exist). 71 | switch.go represents a switch in the network graph 72 | 73 | time_slice.go a single range of time for which a given amount of bandwith has been allocated 74 | 75 | tools.go some generic tools but not generic enough to prompte to the forge packages 76 | 77 | Managers: 78 | globals.go Globals needed by all manager functions and init function 79 | agent.go Manages sessions with agents 80 | http_api.go provides the http "rest-ish" interface 81 | http_mirror_api.go HTTP interface for mirroring 82 | network.go manages the network graph 83 | net_req.go Network manager request struct and related functions 84 | res_mgr.go provides the resevation management logic, suplemented by 85 | three support modules: 86 | res_mgr_bw.go 87 | res_mgr_mirror.go 88 | res_mgr_steer.go 89 | 90 | osif.go openstack interface manager. 91 | osif_proj.go project specific openstack interface functions. 92 | 93 | fqmgr.go flowmod/queue manager 94 | fq_req.go Fqmgr request structure and related functions 95 | fq_mgr_steer.go Steering based fq-mgr support 96 | 97 | res_mgr_bw.go 98 | res_mgr_mirror.go 99 | res_mgr_steer.go 100 | 101 | Testing 102 | tegu_test.go run 'go -v test' to run the tests 103 | 104 | 105 | The tegu source depends on a set of Go packages that were developed along with Tegu, 106 | but are general enough to warrent their not being included here. They are all a part 107 | of the gopkgs/* package library. To use them, clone the git project as described below. 108 | They will be referenced as needed during the build process (unlike C, there is no need 109 | to build a library to link against). Now that tegu is in github, you should be able 110 | to 'go get github/att/gopkgs' to pull them down. 111 | 112 | Go Environment: 113 | The GOPATH variable must be set to the top level directory in your source 114 | tree. Within that directory there should be src, bin, and pkg directories. 115 | Under source there should be a github.com directory which will hold all of your 116 | Go related repos that are checked out of github. 117 | 118 | For example: 119 | export GOPATH=$HOME/godev 120 | cd $GOPATH 121 | mkdir github.com 122 | cd github.com 123 | 124 | # fork a copy of the tegu and gopkgs first!!! 125 | 126 | # replace XXXXX with your user id, then clone your forks 127 | git clone https://XXXXXX@github.com/scm/~XXXXXX/tegu.git 128 | git clone https://XXXXXX@github.com/scm/~XXXXXX/gopkgs.git 129 | 130 | cd tegu 131 | git checkout master # ready to build in lite branch 132 | 133 | Build tegu by: 134 | 1) cd main 135 | 2) go build tegu.go # generates tegu binary 136 | 3) go build tegu_agent.go # builds agent 137 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Tegu 3 | ==== 4 | 5 | Tegu is a reservation manager which provides the ability to create and manage: 6 | * quality of service bandwidth reservations between network endpoints 7 | * flow steering reservations 8 | * wide area network stitching 9 | * port mirroring reservations 10 | 11 | Tegu uses an underlying agent, also included in this repository, to directly manage the 12 | physical components (Open vSwitch or physical switches) as is needed to implement the 13 | reservations. 14 | The underlying agent scripts are contained in the agent directory and the tegu_agent 15 | binary is in the main directory. 16 | 17 | Directory Overview 18 | ------------------ 19 | 20 | The Tegu source is divided into the following subdirectories/packages: 21 | 22 | #### agent/bandwidth 23 | This directory contains various direct interfaces (shell scripts) to things like OVS, 24 | Arista switches, Floodlight (skoogie), etc. 25 | 26 | #### agent/mirror 27 | This directory contains shell scripts used to create and remove mirrors to ports in an 28 | OpenStack environment. 29 | 30 | #### doc 31 | The manual pages for the executables *rjprt*, *tegu*, *tegu_req* and a manual page 32 | describing the Tegu API. 33 | 34 | #### gizmos 35 | Source files which implement objects, interfaces and the functions that operate directly 36 | on them (link, host, switch, pledge, etc.). 37 | 38 | #### main 39 | Entry point functions (*tegu*, *tegu_agent*, and *rjprt*). 40 | 41 | #### managers 42 | Functions that are driven as goroutines and thus implement major components of the 43 | application (reservation manager, fq manager, etc.). 44 | 45 | #### support 46 | Regressions tests. 47 | 48 | #### system 49 | Scripts used to start, stop, and manage Tegu in a Linux environment, as well as the 50 | *tegu_ha* Python script. 51 | 52 | File Overview 53 | ------------- 54 | 55 | Here is an overview of the purpose of some of the .go files in this repository. 56 | 57 | #### gizmos directory 58 | 59 | __fence.go__ - Implements a user limit fence mechanism. 60 | __flight_if.go__ - A floodlight interface providing methods that allow queries to 61 | the controller for gathering link and host information. 62 | __host.go__ - Represents a single host in the network graph and in a path. 63 | __init.go__ - Package level initialization. 64 | __link.go__ - Represents a link between switches in the network graph and in a path. 65 | __lite.go__ - Functions that were implemented quickly to support tegu-lite. 66 | These probably should be moved to separate files, or likely into tools, but during the 67 | hasty implementation of -lite it was easier to keep them bunched here. 68 | __mbox.go__ - Middlebox representation for steering reservations. 69 | __obligation.go__ - Used to manage an obligation of something over time; 70 | references many time slices. 71 | __path.go__ - Manages a path that has been created with a given amount of bandwith. 72 | __pledge.go__ - An interface representing a reservation tracked by resmgr. 73 | Implemented by the various pledge types in the pledge_* files. 74 | __pledge_window.go__ - Manages a time window for pledges and provides basic 75 | *is_active*, *is_expired* functions. 76 | __queue.go__ - Manages information needed to set individual queues for a reservation. 77 | __spq.go__ - A very simple object which allows the return of queue information to 78 | a caller in a single bundle (presently, just the struct, no functions exist). 79 | __switch.go__ - Represents a switch in the network graph. 80 | __time_slice.go__ - A single range of time for which a given amount of bandwith 81 | has been allocated. 82 | __tools.go__ - Some generic tools but not generic enough to put in *gopkgs*. 83 | 84 | #### managers directory 85 | 86 | __fq_mgr.go__ - Flowmod/queue manager. 87 | __fq_mgr_steer.go__ - Steering based FQ-mgr support. 88 | __fq_req.go__ - Fqmgr request structure and related functions. 89 | __globals.go__ - Constants and a few globals shared by \*.go in this directory. 90 | This module also contains the initialisation function that sets all globals up. 91 | __http_api.go__ - Provides the HTTP server, and code to serve URL's under */tegu/api*. 92 | __http_mirror_api.go__ - The HTTP interface for mirroring. 93 | __network.go__ - Manages the network graph. 94 | __net_req.go__ - Network manager request struct and related functions. 95 | __res_mgr.go__ - Provides the reservation management logic, supplemented by three support modules: 96 | *res_mgr_bw.go*, *res_mgr_mirror.go*, and *res_mgr_steer.go*. 97 | __osif.go__ - OpenStack interface manager. 98 | __osif_proj.go__ - Project specific OpenStack interface functions. 99 | 100 | 101 | Building Tegu 102 | ------------- 103 | 104 | The Tegu source depends on a set of Go packages that were developed along with Tegu, 105 | but are general enough to warrant their not being included here. 106 | They are all a part of the `github.com/att/gopkgs` package library. 107 | To use them, clone the git project as described below. 108 | They will be referenced as needed during the build process (unlike C, there is no need 109 | to build a library to link against). 110 | You should be able to do `go get github.com/att/gopkgs` to pull them down. 111 | 112 | ### Go Environment 113 | The GOPATH variable must be set to the top level directory in your source tree. 114 | Within that directory there should be src, bin, and pkg directories. 115 | Under src there should be a github.com directory which will hold all of your 116 | Go related repositories that are checked out of github. 117 | 118 | For example: 119 | 120 | export GOPATH=$HOME/godev 121 | cd $GOPATH 122 | mkdir github.com 123 | cd github.com 124 | 125 | # fork a copy of the tegu and gopkgs first!!! 126 | 127 | # replace XXXXX with your user id, then clone your forks 128 | git clone https://XXXXXX@github.com/~XXXXXX/tegu.git 129 | git clone https://XXXXXX@github.com/~XXXXXX/gopkgs.git 130 | 131 | cd tegu 132 | git checkout master 133 | 134 | Build Tegu by: 135 | 136 | go build main/rjprt.go # builds the rjprt binary 137 | go build main/tegu.go # builds the tegu binary 138 | go build main/tegu_agent.go # builds the tegu agent binary 139 | 140 | What is a Tegu? 141 | --------------- 142 | 143 | A type of lizard (https://en.wikipedia.org/wiki/Tegu). 144 | -------------------------------------------------------------------------------- /agent/README: -------------------------------------------------------------------------------- 1 | This directory contains interface scripts which the tegu-agent 2 | uses to execute direct interaction with switches. 3 | -------------------------------------------------------------------------------- /agent/bandwidth/map_mac2phost.ksh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ksh 2 | # vi: sw=4 ts=4: 3 | # 4 | # --------------------------------------------------------------------------- 5 | # Copyright (c) 2013-2015 AT&T Intellectual Property 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at: 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # --------------------------------------------------------------------------- 19 | # 20 | 21 | # Mnemonic: map_gw2phost 22 | # Abstract: This script accepts a list of hosts and generates a mac to host for 23 | # switches and ports. 24 | # 25 | # Author: E. Scott Daniels 26 | # Date: 04 May 2014 27 | # 28 | # Mods: 11 Aug 2014 - Corrected usage message. 29 | # 14 Oct 2014 - Corrected over stepping after the vlan tag was added to ovs_sp2uuid output 30 | # 09 Dec 2014 - Corrected bug when sussing out port information. 31 | # 09 Jan 2015 - Filter off records that don't have a mac address (-1$) 32 | # 29 Jan 2015 - Added prefix option to allow this to be executed on a local host 33 | # where the operational name of the host doesn't match hostname (e.g. in the DPA1 34 | # environment hostname returns o11r6 but the operational name is o11r6-ops. 35 | # 24 Apr 2015 - Doesn't use the grep return value as the final return value to prevent 36 | # a bad return code if the resulting output is empty (normal if no VMs are on the host). 37 | # ---------------------------------------------------------------------------------------------------------- 38 | 39 | # ---------------------------------------------------------------------------------------------------------- 40 | trap "cleanup" 1 2 3 15 EXIT 41 | 42 | # ensure tmp files go away if we die 43 | function cleanup 44 | { 45 | trap - EXIT 46 | rm -f /tmp/PID$$.* 47 | } 48 | 49 | function logit 50 | { 51 | echo "$(date "+%s %Y/%m/%d %H:%M:%S") $argv0: $@" >&2 52 | } 53 | 54 | function usage 55 | { 56 | cat <<-endKat 57 | 58 | 59 | version 1.0/18114 60 | usage: $argv0 [-n] [-l log-file] [-p record-prefix] [-v] host1 [host2... hostn] 61 | 62 | If -p prefix is given, that prefix is applied to all output records, otherwise 63 | the host name is used. The -p option is intended to be used when only one 64 | host (localhost) is given on the command line and the output of hostname doesn't 65 | match the operational name forcing the use of localhost. 66 | 67 | endKat 68 | 69 | exit 1 70 | } 71 | # -------------------------------------------------------------------------------------------------------------- 72 | 73 | argv0=${0##*/} 74 | 75 | if [[ $argv0 == "/"* ]] 76 | then 77 | PATH="$PATH:${argv0%/*}" # ensure the directory that contains us is in the path 78 | fi 79 | 80 | 81 | forreal=1 82 | verbose=0 83 | log_file="" 84 | 85 | while [[ $1 == -* ]] 86 | do 87 | case $1 in 88 | -n) noexec="-n";; 89 | -l) log_file=$2; shift;; 90 | -p) prefix="$2"; shift;; 91 | -v) verbose=1;; 92 | 93 | -\?) usage 94 | exit 1 95 | ;; 96 | 97 | *) echo "unrecognised option: $1" >&2 98 | usage 99 | exit 1 100 | ;; 101 | esac 102 | shift 103 | done 104 | 105 | if [[ -n $log_file ]] # force stdout/err to a known place; helps when executing from the agent 106 | then 107 | exec >$log_file 2>&1 108 | fi 109 | 110 | if (( $(id -u) != 0 )) 111 | then 112 | sudo="sudo" # must use sudo for the ovs-vsctl commands 113 | fi 114 | 115 | # expected port data from ovs_sp2uuid: 116 | #port: 01f7f621-03ff-43e5-a183-c66151eae9d7 346 tap916a2d34-eb fa:de:ad:54:08:6b 916a2d34-ebdf-402e-bcb3-904b56011773 1 117 | 118 | for h in "$@" 119 | do 120 | rp=${prefix:-$h} # add user supplied prefix, or the hostname to the start of each output record 121 | ovs_sp2uuid -a -h $h any | sed "s/^/$rp /" 122 | done | awk ' 123 | /port:/ && NF >= 6 { # skip internal ports if they were listed 124 | printf( "%s %s\n", $1, $6 ) 125 | } 126 | ' | grep -v -- "-1\$" # dont want entries that have no mac address 127 | exit 0 128 | 129 | -------------------------------------------------------------------------------- /agent/bandwidth/purge_ovs_queues.ksh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ksh 2 | # vi: sw=4 ts=4: 3 | # 4 | # --------------------------------------------------------------------------- 5 | # Copyright (c) 2013-2015 AT&T Intellectual Property 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at: 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # --------------------------------------------------------------------------- 19 | # 20 | 21 | # Mnemonic: purge_ovs_queues 22 | # Abstract: Run though the output of serveral ovs commands looking for QoS entries that 23 | # are not referenced by any ports. For the ones that are not referenced, we'll 24 | # generate a list of associated queues that are also not referenced and delete 25 | # all of the unreferenced things. 26 | # 27 | # Author: E. Scott Daniels 28 | # Date: 24 February 2014 29 | # 30 | # Mods: 23 Apr 2014 - Hacks to allow this to be run centrally. 31 | # 13 May 2014 - Now tracks and purges queues that are 'orphaned'; we purge all 32 | # queues that are unreferenced, not just those that had qos references when 33 | # the script started. Purge all still needed as that purges even queues 34 | # with references. 35 | # 13 May 2014 - Added ssh options to prevent prompts when new host tried 36 | # 10 Nov 2014 - Added connect timeout to ssh calls 37 | # 17 Nov 2014 - Added timeouts on ssh commands to prevent "stalls" as were observed in pdk1. 38 | # 04 Dec 2014 - Ensured that all crit/warn messages have a constant target host component. 39 | # 28 Jan 2014 - To allow agent with ssh-broker to execute on a remote host. 40 | # 16 Mar 2015 - Corrected bug in -h arg processing. 41 | # ---------------------------------------------------------------------------------------------------------- 42 | # 43 | 44 | 45 | function usage 46 | { 47 | cat <<-endKat 48 | 49 | version 1.1/14244 50 | usage: $argv0 [-a] [-n] [-h host] [-v] 51 | 52 | Removes all individual queues and queue combinations (QoSes in OVS terms) from the local OVS environment. 53 | Using -n and -v will indicate at various levels of verbosity what would be done rather than actually 54 | taking the action. 55 | 56 | -a purge all regardless of reference counts 57 | -h host susses queue information from the named host and purges things on that host. 58 | -n no execute mode 59 | -v verbose mode 60 | endKat 61 | } 62 | 63 | # --------------------------------------------------------------------------------------------- 64 | argv0=$0 65 | 66 | shell=ksh 67 | verbose=0 68 | purge_all=0 69 | ssh_host="" # if -h given, this is set to run the ovs commands via ssh on remote host, else we'll just execute here 70 | ssh_opts="-o ConnectTimeout=2 -o StrictHostKeyChecking=no -o PreferredAuthentications=publickey" 71 | forreal=1 72 | limit="" 73 | rhost="localhost=$(hostname)" # target host name for error messages only 74 | 75 | while [[ $1 == -* ]] 76 | do 77 | case $1 in 78 | -a) purge_all=1;; 79 | -h) 80 | if [[ $2 != $(hostname) && $2 != "localhost" ]] 81 | then 82 | ssh_host="ssh $ssh_opts $2"; 83 | rhost="$2" 84 | fi 85 | shift 86 | ;; 87 | 88 | -l) limit+="$2 "; shift;; 89 | -n) forreal=0;; 90 | -v) verbose=1;; 91 | -\?) usage 92 | exit 1 93 | ;; 94 | esac 95 | 96 | shift 97 | done 98 | 99 | 100 | if (( $(id -u) != 0 )) 101 | then 102 | sudo="sudo" # must use sudo for the ovs-vsctl commands 103 | fi 104 | 105 | 106 | ( 107 | cat <<-endKat | timeout 15 $ssh_host ksh # hack to bundle the remote commands since we cannot install software there 108 | $sudo ovs-vsctl list QoS |sed 's/^/QOS /' 109 | $sudo ovs-vsctl list Port | sed 's/^/PORT /' 110 | $sudo ovs-vsctl list Queue | sed 's/^/QUEUE /' 111 | endKat 112 | 113 | if (( $? > 0 )) 114 | then 115 | echo "ERROR!" 116 | fi 117 | )| awk -v limit_lst="${limit:-all}" -v purge_all=${purge_all:-0} -v sudo="$sudo" -v verbose=$verbose ' 118 | BEGIN { 119 | n = split( limit_lst, a, " " ) 120 | for( i = 1; i <= n; i++ ) 121 | lmit[a[i]] = 1 122 | } 123 | 124 | /ERROR!/ { 125 | print "ERROR!"; 126 | next; 127 | } 128 | 129 | /QOS _uuid/ { 130 | qos[$NF] = 1; 131 | cur_qos = $NF; 132 | next; 133 | } 134 | 135 | /QUEUE _uuid/ { # track all queues, not just those associated with a qos so we purge all orphaned queues at end 136 | qrefcount[$NF] += 0; 137 | next; 138 | } 139 | 140 | /^switch: / && NF > 1 { # collect switch data for purge-all 141 | if( limit["all"] || limit[$2] || limit[$4] ) 142 | pa_cur_switch = $2; 143 | else 144 | pa_cur_switch="" 145 | next; 146 | } 147 | 148 | /^port: / && NF > 1 { # collect switch/port info for purge all 149 | if( pa_cur_switch != "" ) 150 | swpt2uuid[pa_cur_switch"-"$NF] = $2; 151 | next; 152 | } 153 | 154 | /QOS queues/ { 155 | for( i = 3; i <= NF; i++ ) 156 | { 157 | gsub( "}", "", $(i) ); 158 | gsub( ",", "", $(i) ); 159 | split( $(i), a, "=" ); 160 | qos2queue[cur_qos] = qos2queue[cur_qos] a[2] " "; 161 | qrefcount[a[2]]++; 162 | nqueues[cur_qos]++; 163 | } 164 | } 165 | 166 | /PORT _uuid/ { 167 | cur_port = $NF; 168 | next; 169 | } 170 | /PORT qos/ { 171 | port2qos[cur_port] = $NF; 172 | qos_ref[$NF] = 1; 173 | next; 174 | } 175 | 176 | END { 177 | if( purge_all ) # drop queues from all switches first else queue/qos deletes fail 178 | { 179 | for( s in port2qos ) 180 | printf( "%s ovs-vsctl clear Port %s qos\n", sudo, s ); 181 | } 182 | 183 | qlidx = 0; # index into qos list 184 | for( x in nqueues ) 185 | { 186 | if( purge_all || ! qos_ref[x] ) # unreferenced queue combination 187 | { 188 | if( verbose ) 189 | printf( "delete qos: %s\n", x ) >"/dev/fd/2"; 190 | printf( "%s ovs-vsctl destroy QoS %s\n", sudo, x ); # should use --if-exists, but backlevel ovs used with openstack prevents this 191 | 192 | n = split( qos2queue[x], a, " " ) # deref each individual queue in the group 193 | for( i = 1; i <= n; i++ ) 194 | qrefcount[a[i]]--; 195 | } 196 | else 197 | if( verbose ) 198 | printf( "keep qos: %s\n", x ) >"/dev/fd/2"; 199 | } 200 | 201 | for( x in qrefcount ) # del any individual queues that ended up with a 0 refcount 202 | if( x != "" && (purge_all || qrefcount[x] <= 0) ) 203 | { 204 | printf( "%s ovs-vsctl destroy Queue %s\n", sudo, x ); 205 | if( verbose ) 206 | printf( "delete queue: %s\n", x ) >"/dev/fd/2"; 207 | } 208 | else 209 | if( x != "" && verbose ) 210 | printf( "keep queue: %s\n", x ) >"/dev/fd/2"; 211 | } 212 | ' >/tmp/PID$$.cmds2 # snag cmds to execute in bulk if running through ssh 213 | 214 | if ! grep -q "ERROR!" /tmp/PID$$.cmds2 215 | then 216 | if [[ -s /tmp/PID$$.cmds2 ]] 217 | then 218 | if (( forreal )) 219 | then 220 | $ssh_host ksh &2 228 | fi 229 | 230 | rm -f /tmp/PID$$.* 231 | 232 | exit 233 | 234 | 235 | 236 | 237 | 238 | _uuid : c383cc20-7f05-45eb-9d75-1ce2b5adfbb8 239 | bond_downdelay : 0 240 | bond_fake_iface : false 241 | bond_mode : 242 | bond_updelay : 0 243 | external_ids : 244 | fake_bridge : false 245 | interfaces : f2d71458-67ce-4279-9e4c-b2f73c405544 246 | lacp : 247 | mac : 248 | name : s7-eth2 249 | other_config : 250 | qos : 251 | statistics : 252 | status : 253 | tag : 254 | trunks : 255 | vlan_mode : 256 | 257 | -------------------------------------------------------------------------------- /agent/bandwidth/ql_bwow_fmods.ksh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ksh 2 | # vi: sw=4 ts=4: 3 | # 4 | # --------------------------------------------------------------------------- 5 | # Copyright (c) 2013-2015 AT&T Intellectual Property 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at: 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # --------------------------------------------------------------------------- 19 | # 20 | 21 | # Mnemonic: ql_bwow_fmods 22 | # Abstract: Generates all needed flow-mods on an OVS for a oneway bandwidth reservation. 23 | # One way reservations mark and potentially rate limit traffic on the ingress 24 | # OVS only. There is no attempt to set any flow-mods for inbound traffic as 25 | # we do NOT expect that the traffic has been marked by us on the way "in". 26 | # A oneway reservation is generally implemented when the other endpint is 27 | # external (cross project, or on the other side of the NAT box), and the router 28 | # is not a neutron router (i.e. not under OVS). 29 | # 30 | # Bandwidth reservation flow mods are set up this way: 31 | # inbound (none) 32 | # 33 | # outbound 34 | # p400 Match: 35 | # meta == 0 && 36 | # reservation VM0 && 37 | # external-IP [&& proto:port] 38 | # Action: 39 | # mark with meta value (-M) 40 | # set dscp value 41 | # resub 0 to apply openstack fmods 42 | # 43 | # We no longer need to set VLAN on outbound nor do we need to strip VLAN on inbound, so 44 | # vlan options are currently ignored (supported to be compatible with old/unchanged 45 | # agents). Same with queues. We aren't queuing at the moment so the queue options are 46 | # ignored. In future, there will (should) be a concept of flow-limits (meters maybe) 47 | # which will be passed in as queue numbers, so the -q option needs to be kept and should 48 | # be expected and used when the underlying network compoents can support it. 49 | # 50 | # Date: 15 June 2015 51 | # Author: E. Scott Daniels 52 | # 53 | # Mods: 17 Jun 2015 - Corrected handling of queue value when 0. 54 | # 03 Feb 2016 - Tweak to support any destination as a remote endpoint. 55 | # --------------------------------------------------------------------------------------------------------- 56 | 57 | function logit 58 | { 59 | echo "$(date "+%s %Y/%m/%d %H:%M:%S") $argv0: $@" >&2 60 | } 61 | 62 | function usage 63 | { 64 | echo "$argv0 v1.0/16155" 65 | echo "usage: $argv0 [-6] [-d dst-mac] [-E external-ip] [-h host] [-n] [-p|P proto:port] [-s src-mac] [-T dscp] [-t hard-timeout]" 66 | echo "usage: $argv0 [-X] # delete all" 67 | echo "" 68 | echo " -6 forces IPv6 address matching to be set" 69 | } 70 | 71 | 72 | # ---------------------------------------------------------------------------------------------------------- 73 | 74 | cookie="0xf00d" # static for now, but might want to make them user controlled, so set them up here 75 | bridge="br-int" 76 | mt_base=90 # meta table base 90 sets 0x01, 91 sets 0x02, 94 sets 0x04... 77 | 78 | smac="" # src mac address (local to this OVS) 79 | dmac="" # dest mac (remote if not x-project) 80 | exip="" # external (dest) IP address (if x-project, or dest proto supplied) 81 | queue="" 82 | idscp="" 83 | odscp="" 84 | host="" 85 | forreal="" 86 | pri_base=0 # priority is bumpped up a bit for protocol specific f-mods 87 | queue="0" 88 | to_value="61" # value used to check (without option flag) 89 | timout="-t $to_value" # timeout parm given on command 90 | operation="add" # -X sets delete action 91 | ip_type="-4" # default to forcing an IP type match for outbound fmods; inbound fmods do NOT use this 92 | 93 | while [[ $1 == -* ]] 94 | do 95 | case $1 in 96 | -6) ip_type="-6";; # force ip6 option to be given to send_ovs_fmod 97 | -d) dmac="-d $2"; shift;; # dest (remote) mac address (could be missing) 98 | -E) exip="$2"; shift;; 99 | -h) host="-h $2"; shift;; 100 | -n) forreal="-n";; 101 | -p) pri_base=5; sproto="-p $2"; shift;; # source proto:port priority must increase to match over more generic f-mods 102 | -P) pri_base=5; dproto="-P $2"; shift;; # dest proto:port priority must increase to match over more generic f-mods 103 | -q) queue="$2"; shift;; # ignored until HTB replacedment is found 104 | -s) smac="$2"; shift;; # source (local) mac address 105 | -S) sip="-S $2"; shift;; # local IP needed if local port (-p) is given 106 | -t) to_value=$2; timeout="-t $2"; shift;; 107 | -T) odscp="-T $2"; shift;; 108 | -V) match_vlan="-v $2"; shift;; 109 | -X) operation="del";; 110 | 111 | -\?) usage 112 | exit 0 113 | ;; 114 | 115 | *) echo "unrecognised option: $1" 116 | usage 117 | exit 1 118 | ;; 119 | esac 120 | 121 | shift 122 | done 123 | 124 | if [[ -z $smac ]] 125 | then 126 | logit "must have source mac address in order to generate oneway flow-mods [FAIL]" 127 | exit 1 128 | fi 129 | 130 | open_dest=0 131 | if [[ $exip == "any" ]] 132 | then 133 | exip="" 134 | open_dest=1 135 | else 136 | if [[ -n $exip ]] 137 | then 138 | exip="-D $exip" 139 | fi 140 | fi 141 | 142 | if (( ! open_dest )) # if not an open destination (!//any not supplied as second host) 143 | then 144 | if [[ -z $dmac && -z $exip ]] # fail if both missing 145 | then 146 | logit "must have either destination mac address or external IP address to generate oneway flow-mods; both missing [FAIL]" 147 | exit 1 148 | fi 149 | fi 150 | 151 | if (( queue > 0 )) 152 | then 153 | echo "-q $queue was ignored: no htb queuing allowed [OK]" 154 | queue="" 155 | #queue="-q $queue" 156 | else 157 | queue="" 158 | fi 159 | 160 | # CAUTION: action options to send_ovs_fmods are probably order dependent, so be careful. 161 | set -x 162 | send_ovs_fmod $forreal $host $timeout -p $(( 400 + pri_base )) --match $match_vlan $ip_type -m 0x0/0x7 $sip $exip -s $smac $dmac $dproto $sproto --action $queue $odscp -M 0x01 -R ,0 -N $operation $cookie $bridge 163 | rc=$(( rc + $? )) 164 | set +x 165 | 166 | rm -f /tmp/PID$$.* 167 | if (( rc )) 168 | then 169 | exit 1 170 | fi 171 | 172 | exit 0 173 | -------------------------------------------------------------------------------- /agent/bandwidth/ql_filter_rtr.ksh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ksh 2 | # vi: sw=4 ts=4: 3 | # 4 | # --------------------------------------------------------------------------- 5 | # Copyright (c) 2013-2015 AT&T Intellectual Property 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at: 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # --------------------------------------------------------------------------- 19 | # 20 | 21 | # Mnemonic: ql_fiilter_rtr 22 | # Abstract: Run various ip commands to get a list of router/gw mac addresses that are currently 23 | # active on the node. Using the list, and the output from ovs_sp2uuid (stdin) 24 | # generate an augmented set of ovs_sp2uuid output. The filter applied allows all 25 | # non-router elements to pass, and blocks router elements if there is no corresponding 26 | # mac address listed by the series of ip commands. 27 | # 28 | # Running through the name spaces seems to be expensive, based on a trial on a loaded L3, 29 | # so we'll cache the list and regenerate it only if we think it is out of date. 30 | # 31 | # DANGER: This can be _extremely_ expensive (in terms of wall clock execution time) 32 | # and thus any code that calls it, and is expected to return a result quickly 33 | # might not. The run time is proportional to the number of routers that are 34 | # existing on the host (readl longer for an L3). 35 | # 36 | # Author: E. Scott Daniels 37 | # Date: 14 April 2015 38 | # -------------------------------------------------------------------------------------------------- 39 | 40 | 41 | age=300 # reload only every 5 minutes by default 42 | while [[ $1 == -* ]] 43 | do 44 | case $1 in 45 | -a) age=$2; shift;; 46 | -f) age=0;; # force a reload of data regardless of how old the cache is 47 | 48 | *) echo "unrecognised option $1" 49 | echo "usage: $0 [-a age|-f] [data-file]" 50 | echo "data file is the output from ovs_sp2uuid; if omitted the output is assumed to be on stdin" 51 | exit 1 52 | ;; 53 | esac 54 | 55 | shift 56 | done 57 | 58 | user=${USER:-$LOGNAME} # one of these should be set; prevent issues if someone runs manually 59 | cache=/tmp/ql_rmac_${user}.cache 60 | if [[ -f /tmp/ql_filter_rtr.v ]] # preliminary testing; delete next go round of changes 61 | then 62 | verbose=1 63 | fi 64 | 65 | need=0 66 | if [[ ! -s $cache ]] # generate if empty or missing 67 | then 68 | need=1 69 | else 70 | ts=$( stat -c %Y $cache ) # last mod time of the cache 71 | now=$( date +%s ) 72 | if (( now - ts > age )) 73 | then 74 | need=1 75 | fi 76 | fi 77 | 78 | if (( need )) 79 | then 80 | echo "snarfing netns data" 81 | ip netns | grep "qrouter-" | while read r # suss out the list of router name spaces 82 | do 83 | if (( verbose )) 84 | then 85 | echo "suss from $r [OK]" >&2 86 | fi 87 | sudo ip netns exec $r ifconfig | grep HWaddr # query each name space, get all associated mac addresses 88 | done >/tmp/PID$$.cache # prevent accidents if multiple copies running 89 | 90 | mv /tmp/PID$$.cache $cache # if multiple copies running, this is atomic 91 | fi 92 | 93 | ( 94 | awk '{ print $NF }' $cache | sort -u | sed 's/^/mac: /' # mac addresses MUST be first 95 | cat $1 # useful use of cat -- read stdin or from file if given 96 | ) | awk ' 97 | /^mac: / { # collect mac addresses 98 | mac[$2] = 1; 99 | next; 100 | } 101 | 102 | /^port.*qg-/ { # allow to pass only if a mac address was seen 103 | if( mac[$5] == 1 ) 104 | print; 105 | next; 106 | } 107 | 108 | /^port.*qr-/ { 109 | if( mac[$5] == 1 ) 110 | print; 111 | next; 112 | } 113 | 114 | { print; next; } 115 | ' 116 | 117 | exit 0 118 | -------------------------------------------------------------------------------- /agent/bandwidth/ql_pass_fmods.ksh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ksh 2 | # vi: sw=4 ts=4: 3 | # 4 | # --------------------------------------------------------------------------- 5 | # Copyright (c) 2013-2015 AT&T Intellectual Property 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at: 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # --------------------------------------------------------------------------- 19 | # 20 | 21 | # Mnemonic: ql_pass_fmods 22 | # Abstract: Generates all needed flow-mods on an OVS for a passthrough reseration. 23 | # The passthrough reservation allows a VM to set its own DSCP markings which 24 | # our priority 10 flow-mod doesn't reset to 0 as the traffic goes out. 25 | # 26 | # Flow mods are set up this way: 27 | # inbound (none) 28 | # 29 | # outbound 30 | # p400 Match: 31 | # meta == 0 && 32 | # reservation VM mac 33 | # [potocol and port] 34 | # Action: 35 | # mark with meta value (-M) 36 | # 37 | # 38 | # Date: 26 January 2016 39 | # Author: E. Scott Daniels 40 | # 41 | # Mods: 42 | # --------------------------------------------------------------------------------------------------------- 43 | 44 | function logit 45 | { 46 | echo "$(date "+%s %Y/%m/%d %H:%M:%S") $argv0: $@" >&2 47 | } 48 | 49 | function usage 50 | { 51 | echo "$argv0 v1.0/11216" 52 | echo "usage: $argv0 -s src-mac|endpoint [-n] [-S procol:[address:]port] [-t hard-timeout]" 53 | echo "usage: $argv0 [-X] # delete all" 54 | echo "For -S address can be ipv4 or ipv6; ipv6 must be in brackets. Port should be 0 for all ports" 55 | } 56 | 57 | # given a string that could be mac or endpoint, convert to mac and return the mac and the 58 | # bridge that we found it on. If a mac is passed in, we don't return a bridge as there 59 | # could be duplicate mac addresses out there (different vlans) so we can't be sure which 60 | # bridge the mac is on. 61 | function ep2mac 62 | { 63 | if [[ $1 == *":"* ]] 64 | then 65 | echo "$1" "" 66 | fi 67 | 68 | typeset sw="" 69 | typeset mac="" 70 | ovs_sp2uuid -a | awk -v target="$1" ' 71 | /^switch:/ { 72 | sw = $NF; 73 | next; 74 | } 75 | /^port: / { 76 | if( NF > 6 ) { 77 | if( target == $2 ) { 78 | print $5, sw; 79 | exit( 0 ) 80 | } 81 | } 82 | } 83 | ' | read mac sw 84 | 85 | if [[ -z $sw ]] 86 | then 87 | echo "$1" "" 88 | fi 89 | 90 | echo "$mac" "$sw" 91 | } 92 | 93 | # Accept proto:[address:]port and split them echoing three strings: proto, addr, port 94 | # if address is missing the string 'none' is echoed. The global variable ip_type is set 95 | # based on the address type and left alone if just the port was supplied. 96 | function split_pap 97 | { 98 | typeset proto="" 99 | typeset rest="" 100 | typeset addr="" 101 | 102 | case $1 in # split proto:rest 103 | *:\[* | *:*.*) # proto:ipv6 or proto:ipv4 104 | proto=${1%%:*} 105 | rest=${1#*:} 106 | ;; 107 | 108 | \[*\]:* | *.*:*) # address:port (no proto) 109 | proto="" 110 | rest="$1" 111 | ;; 112 | 113 | *::*) # proto::port (empty address) 114 | proto="${1%%:*}" 115 | rest="${1##*:}" 116 | ;; 117 | 118 | *:*) # proto:port ('empty' address) 119 | proto="${1%:*}" 120 | rest="${1#*:}" 121 | ;; 122 | 123 | *) # assume lone udp/tcp and no :addr:port or :port 124 | proto=$1 125 | rest="" 126 | ;; 127 | esac 128 | 129 | 130 | if [[ -z $rest ]] # only proto given 131 | then 132 | echo "$proto none 0" 133 | fi 134 | 135 | case "$rest" in 136 | \[*\]*) # ipv6 address:port or just ipv6 137 | addr="${rest%%]*}" 138 | ip_type="-6" # must force the type; set directly, DO NOT use set_ip_type 139 | if [[ $rest == *"]:"* ]] 140 | then 141 | rest="${rest##*]:}" 142 | rest="${rest:-0}" # handle case where : exists, but no port (implied 0) 143 | proto=${proto:-tcp} # if there is a port we must ensure there is a prototype; default if not given 144 | else 145 | rest="${rest##*]}" 146 | fi 147 | echo "${proto:-none} "[${addr##*\[}]" ${rest:-0}" 148 | ;; 149 | 150 | *.*.*.*) # ipv4:port or just ipv4 151 | ip_type="-4" 152 | addr="${rest%%:*}" 153 | if [[ $rest == *:* ]] 154 | then 155 | rest="${rest##*:}" 156 | proto=${proto:-tcp} # if there is a port we must ensure there is a prototype; default if not given 157 | else 158 | rest=0 159 | fi 160 | 161 | echo "$proto $addr ${rest:-0}" 162 | ;; 163 | 164 | *) # just port; default ip type, or what they set on command line 165 | echo "$proto none ${rest//:/}" 166 | ;; 167 | esac 168 | } 169 | 170 | # check the current setting of ip_type and return $1 only if it's not set. If it's set 171 | # return the current setting. This prevents ip_type from being set by the pap function 172 | # and then incorrectly overridden from a comand line option. 173 | function set_ip_type 174 | { 175 | if [[ -n $ip_type ]] 176 | then 177 | echo $ip_type 178 | else 179 | echo "$1" 180 | fi 181 | } 182 | 183 | # ---------------------------------------------------------------------------------------------------------- 184 | 185 | cookie="0x0dad" # static for now, but might want to make them user controlled, so set them up here 186 | bridge="br-int" 187 | 188 | smac="" # src mac address (local to this OVS) 189 | forreal="" 190 | to_value=60 # default timeout value 191 | timout="-t $to_value" # timeout parm given on command if -t not supplied 192 | operation="add" # -X sets delete action 193 | ip_type="" # default unless we see a specific address 194 | 195 | while [[ $1 == -* ]] 196 | do 197 | case $1 in 198 | -4) ip_type="$(set_ip_type $2);; # set if not set; don't let them override what was set in pap 199 | -6) ip_type="$(set_ip_type $2);; # set if not set; don't let them override what was set in pap 200 | -n) forreal="-n";; 201 | -s) smac="$2"; shift;; # source (local) mac address (should be endpoint to be safe, but allow mac) 202 | -S) split_pap "$2" | read proto sip port # expect -S {udp|tcp}:[address:]port 203 | echo ">>> ($proto) ($sip) ($port)" 204 | if [[ $sip == "none" ]] 205 | then 206 | sip="" 207 | else 208 | sip="-S $sip" 209 | fi 210 | shift 211 | ;; 212 | 213 | -t) to_value=$2; timeout="-t $2"; shift;; # capture both the value for math, and an option for flow-mod call 214 | -T) odscp="-T $2"; shift;; 215 | -X) operation="del";; 216 | 217 | -\?) usage 218 | exit 0 219 | ;; 220 | 221 | *) echo "unrecognised option: $1" 222 | usage 223 | exit 1 224 | ;; 225 | esac 226 | 227 | shift 228 | done 229 | 230 | if [[ -z $smac ]] 231 | then 232 | logit "must have source endpoint (better) or mac address (unsafe) in order to generate passthrough flow-mods [FAIL]" 233 | exit 1 234 | fi 235 | 236 | ep2mac $smac | read ep_mac ep_switch # convert endpoint to mac, and the get bridge name (if it is an endpoint) 237 | if [[ -n $ep_switch ]] # it converted if switch isn't blank 238 | then 239 | logit "endpoint $smac converted to mac/switch: $ep_mac/$ep_switch [INFO]" 240 | smac=$ep_mac 241 | bridge=$ep_switch 242 | else 243 | logit "$smac seems not to be an endpoint, used directly with bridge $bridge [INFO]" 244 | fi 245 | 246 | if false 247 | then 248 | if [[ -n $sproto && -z sip ]] # must have a source IP if source proto is supplied 249 | then 250 | logit "source IP address (-S) required when prototype (-p) is supplied [FAIL]" 251 | exit 1 252 | fi 253 | fi 254 | 255 | if [[ $proto == "none" ]] 256 | then 257 | proto="" 258 | else 259 | if [[ -n $proto ]] 260 | then 261 | proto="-p $proto:$port" 262 | fi 263 | fi 264 | 265 | # the flow-mod is simple; match and set marking that causes the p10 flow-mod from matching. 266 | set -x 267 | send_ovs_fmod $forreal $timeout -p 400 --match -m 0x0/0x7 $sip -s $smac $proto --action -M 0x01 -R ,0 -N $operation $cookie $bridge 268 | rc=$(( rc + $? )) 269 | set +x 270 | 271 | rm -f /tmp/PID$$.* 272 | if (( rc )) 273 | then 274 | exit 1 275 | fi 276 | 277 | exit 0 278 | -------------------------------------------------------------------------------- /agent/bandwidth/ql_set_trunks.ksh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ksh 2 | # vi: sw=4 ts=4: 3 | # 4 | # --------------------------------------------------------------------------- 5 | # Copyright (c) 2013-2015 AT&T Intellectual Property 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at: 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # --------------------------------------------------------------------------- 19 | # 20 | 21 | # Mnemonic: ql_set_trunks 22 | # Abstract: Read the output from ovs_sp2uuid and suss off all VLAN IDs for br-int. Then 23 | # generate a trunk command that adds the trunk list to the qosirl0 interface. 24 | # Trunks must be set on the interface in order to set the vlan-id in a flow-mod 25 | # as data passes to the interface. Trunks canNOT be set as a range. 26 | # 27 | # As of OVS 2.1 it seems that the listing of VLAN IDs on a trunk port isn't 28 | # needed, so this script may now be deprecated. 29 | # 30 | # To delete all VLAN IDs from the trunk list: 31 | # ovs-vsctl remove port 94da17a2-5042-476a-8a49-1e112e273c14 trunks 2,3,7,8,9,17,4095 32 | # 33 | # Author: E. Scott Daniels 34 | # Date: 09 April 2015 35 | # 36 | #--------------------------------------------------------------------------------------------- 37 | 38 | forreal="" 39 | 40 | while [[ $1 == -* ]] 41 | do 42 | case $1 in 43 | -n) forreal="echo would execute: ";; 44 | 45 | -\?) echo "usage: $0 [-n]" 46 | exit 0 47 | ;; 48 | 49 | *) echo "usage: $0 [-n]" 50 | exit 1 51 | ;; 52 | esac 53 | 54 | shift 55 | done 56 | 57 | ovs_sp2uuid -a | awk ' 58 | /^switch:/ { 59 | snarf = 0 60 | if( $NF == "br-int" ) 61 | snarf = 1 62 | next; 63 | } 64 | 65 | /^port:.*qosirl0/ { # port id for the ovs-vsctl command 66 | irl_id = $2; 67 | next; 68 | } 69 | 70 | /^port:/ && NF > 6 { # this will work when sp2uuid starts to generate constant fields 71 | if( $7 > 0 ) { 72 | seen[$7] = 1 73 | if( $7 > max ) 74 | max = $7 75 | } 76 | next; 77 | } 78 | 79 | END { 80 | sep = "" 81 | list = "" 82 | for( i = 1; i <= max; i++ ) { # keeps them sorted 83 | if( seen[i] ) { 84 | list = list sprintf( "%s%d", sep, i ) 85 | sep = "," 86 | } 87 | } 88 | 89 | if( irl_id != "" ) { 90 | printf( "sudo ovs-vsctl set port %s trunks=%s\n", irl_id, list ) 91 | } else { 92 | printf( "ERR: unable to find qosirl0 interface in ovs_sp2uuid list\n" ) >"/dev/fd/2" 93 | exit( 1 ) 94 | } 95 | } 96 | '| read cmd 97 | 98 | if [[ -n $cmd ]] 99 | then 100 | $forreal $cmd 101 | else 102 | "ERR no trunk command generated" 103 | exit 1 104 | fi 105 | 106 | exit 0 107 | 108 | -------------------------------------------------------------------------------- /agent/bandwidth/ql_setup_irl.ksh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # vi: sw=4 ts=4: 3 | # 4 | # --------------------------------------------------------------------------- 5 | # Copyright (c) 2013-2015 AT&T Intellectual Property 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at: 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # --------------------------------------------------------------------------- 19 | # 20 | 21 | # ----------------------------------------------------------------------------------------------------------------- 22 | # Mnemonic: ql_setup_irl.ksh 23 | # Abstract: Sets up ingress rate limiting bridge veth connector and flow-mods. 24 | # 25 | # Author: E. Scott Daniels 26 | # Date: 22 September 2014 27 | # 28 | # Mods: 07 Oct 2014 - bug fix #227 - Only puts in flow mods when bridge is created 29 | # 15 Oct 2014 - corrected bug introduced with #227 that was causing the br-rl f-mod 30 | # not to be created if it was deleted after the bridge was setup. 31 | # 27 Oct 2014 - bug fix #241 32 | # 10 Nov 2014 - Added connect timeout to ssh calls 33 | # 17 Nov 2014 - Added timeouts on ssh commands to prevent "stalls" as were observed in pdk1. 34 | # 04 Dec 2014 - Ensured that all crit/warn messages have a constant target host component. 35 | # 28 Jan 2015 - Prevent an ssh call if -h indicates local host. 36 | # ----------------------------------------------------------------------------------------------------------------- 37 | 38 | function logit 39 | { 40 | echo "$(date "+%s %Y/%m/%d %H:%M:%S") $rhost $argv0: $@" >&2 41 | } 42 | 43 | function ensure_ok 44 | { 45 | if (( $1 > 100 )) # timeout 46 | then 47 | shift 48 | logit "abort: ssh timout: $@ target-host: $rhost [FAIL]" 49 | rm -f $tmp/PID$$.* 50 | exit 1 51 | fi 52 | 53 | if (( $1 != 0 )) 54 | then 55 | shift 56 | logit "abort: $@ target-host: $rhost [FAIL]" 57 | rm -f $tmp/PID$$.* 58 | exit 1 59 | fi 60 | } 61 | 62 | function warn_if_bad 63 | { 64 | if (( $1 != 0 )) 65 | then 66 | shift 67 | logit "$@ [WARN]" 68 | fi 69 | } 70 | 71 | # create the rate limit bridge 72 | function mk_bridge 73 | { 74 | $forreal timeout 15 $ssh $sudo /usr/bin/ovs-vsctl add-br br-rl 75 | ensure_ok $? "unable to make bridge br-rl" 76 | logit "created bridge br-rl" 77 | } 78 | 79 | # remove the bridge 80 | function rm_bridge 81 | { 82 | logit "deleting bridge br-rl" 83 | $forreal timeout 15 $ssh $sudo /usr/bin/ovs-vsctl del-br br-rl 84 | } 85 | 86 | # create our veth that will be used for the loop round 87 | function mk_veth 88 | { 89 | $forreal timeout 15 $ssh $sudo ip link add $ve0 type veth peer name $ve1 90 | ensure_ok $? "unable to create veth link $ve0-$ve1" 91 | 92 | $forreal timeout 15 $ssh $sudo ip link set dev $ve0 up 93 | ensure_ok $? "unable to bring up veth link end point $ve0" 94 | 95 | $forreal timeout 15 $ssh $sudo ip link set dev $ve1 up 96 | ensure_ok $? "unable to bring up veth link end point $ve1" 97 | logit "created veth pair $ve0-$ve1 [OK]" 98 | } 99 | 100 | # delete the veth link 101 | function rm_veth 102 | { 103 | logit "deleting link" 104 | $forreal timeout 15 $ssh $sudo ip link set dev $ve0 down 105 | $forreal timeout 15 $ssh $sudo ip link set dev $ve1 down 106 | $forreal timeout 15 $ssh $sudo ip link delete $ve0 type veth peer name $ve1 107 | } 108 | 109 | # detach the ports -- ignore output and return codes 110 | function detach_veth 111 | { 112 | $forreal timeout 15 $ssh $sudo ovs-vsctl del-port $ve0 >/dev/null 2>&1 113 | $forreal timeout 15 $ssh $sudo ovs-vsctl del-port $ve1 >/dev/null 2>&1 114 | } 115 | 116 | # attach the veth to br-int and br-rl 117 | function attach_veth 118 | { 119 | logit "cleaning previous attachments: $ve0-$ve1 to br-int and br-rl [OK]" 120 | # drop the ports if one or the other were already there (ignoring failures) 121 | detach_veth 122 | 123 | $forreal timeout 15 $ssh $sudo ovs-vsctl add-port br-int $ve0 #-- set interface $ve0 ofport=4000 124 | ensure_ok $? "unable to attach veth $ve0 to br-int" 125 | 126 | $forreal timeout 15 $ssh $sudo ovs-vsctl add-port br-rl $ve1 #-- set interface $ve1 ofport=4001 127 | ensure_ok $? "unable to attach veth $ve1 to br-rl" 128 | 129 | logit "attached $ve0-$ve1 to br-int and br-rl [OK]" 130 | } 131 | 132 | function usage 133 | { 134 | echo "$argv0 version 1.0/19224" >&2 135 | echo "usage: $argv0 [-D] [-h host] [-n] [-p link-prefix]" >&2 136 | echo " -D causes all rate limiting bridges, ports and links to be removed" 137 | } 138 | 139 | # ------------------------------------------------------------------------------------------- 140 | if (( $( id -u ) != 0 )) 141 | then 142 | sudo="sudo" 143 | fi 144 | 145 | tmp=${TMP:-/tmp} 146 | argv0="${0##*/}" 147 | ssh_opts="-o ConnectTimeout=2 -o StrictHostKeyChecking=no -o PreferredAuthentications=publickey" 148 | 149 | ssh="" # if -h given, these get populated with needed remote host information 150 | rhost="$(hostname)" # remote host name for messages 151 | rhost_parm="" # remote host parameter (-h xxx) for commands that need it 152 | 153 | forreal="" 154 | no_exe="" 155 | traceon="set -x" 156 | traceoff="set +x" 157 | link_prefix="qosirl" 158 | force_attach=0 159 | delete=0 160 | 161 | while [[ $1 == "-"* ]] 162 | do 163 | case $1 in 164 | -D) delete=1;; 165 | -h) 166 | if [[ $2 != $rhost && $2 != "localhost" ]] 167 | then 168 | rhost="$2" 169 | rhost_parm="-h $2" 170 | ssh="ssh -n $ssh_opts $2" # CAUTION: this MUST have -n since we don't redirect stdin to ssh 171 | fi 172 | shift 173 | ;; 174 | 175 | -n) 176 | no_exec="-n" 177 | forreal="echo noexec (-n) is set, would run: " 178 | traceon="" 179 | traceoff="" 180 | ;; 181 | 182 | -p) link_prefix="$2"; shift;; 183 | 184 | -\?) usage; 185 | exit;; 186 | esac 187 | 188 | shift 189 | done 190 | 191 | ve0="${link_prefix}0" # veth endpoint names 192 | ve1="${link_prefix}1" 193 | 194 | if (( delete )) 195 | then 196 | logit "deleting ingress rate limiting configuration (bridge, ports, veth pair) [OK]" 197 | detach_veth # bring the ports down and remove from the bridges 198 | rm_veth # delete the link 199 | rm_bridge # finally drop the bridge 200 | 201 | exit 0 202 | fi 203 | 204 | if [[ -e /etc/tegu/no_irl ]] 205 | then 206 | logit "abort: /etc/tegu/no_irl file exists which prevents setting up ingress rate limiting bridge and flow-mods [WARN]" 207 | exit 1 208 | fi 209 | 210 | bridge_list=/tmp/PID$$.brdge 211 | link_list=/tmp/PID$$.link 212 | 213 | timeout 15 $ssh $sudo ovs-vsctl -d bare list bridge|grep name >$bridge_list 214 | ensure_ok $? "unable to get bridge list" 215 | 216 | add_fmod=0 217 | if ! grep -q br-rl $bridge_list 218 | then 219 | mk_bridge 220 | force_attach=1 221 | add_fmod=1 # no flow-mod if new bridge; cause creation 222 | else 223 | timeout 15 $ssh $sudo ovs-ofctl dump-flows br-rl |grep -q cookie=0xdead 224 | if (( $? > 0 )) 225 | then 226 | add_fmod=1 # f-mod gone missing; force creation 227 | fi 228 | fi 229 | 230 | if (( add_fmod )) 231 | then 232 | # bug fix #227 -- only replace the flow mod when bridge is created, or if we cannot find it 233 | send_ovs_fmod $rhost_parm $no_exec -t 0 --match --action -b add 0xdead br-rl # default f-mod for br-rl that bounces packets out from whence they came 234 | ensure_ok $? "unable to set flow-mod on br-rl" 235 | fi 236 | 237 | timeout 15 $ssh ip link > $link_list 238 | ensure_ok $? "unable to generate a list of links" 239 | 240 | if ! grep -q "$link_prefix" $link_list # no veth found, make it 241 | then 242 | mk_veth 243 | attach_veth 244 | else 245 | c=0 246 | if (( ! force_attach )) # don't need to spend time if force was set 247 | then 248 | ovs_sp2uuid $rhost_parm -a >/tmp/PID$$.udata # fix #241; ensure that veth are attached to bridges 249 | ensure_ok $? "unable to get ovs uuid data from $rhost" 250 | c=$( grep -c $link_prefix /tmp/PID$$.udata ) 251 | fi 252 | if (( c != 2 )) # didn't exist, or pair existed, but if we had to create br-rl then we must attach it 253 | then 254 | attach_veth 255 | fi 256 | fi 257 | 258 | 259 | $forreal timeout 15 $ssh $sudo ovs-ofctl mod-port br-int $ve0 noflood # we should always do this 260 | warn_if_bad $? "unable to set no flood on br-int:$ve0" 261 | 262 | 263 | rm -f $tmp/PID$$.* 264 | exit 0 265 | 266 | 267 | -------------------------------------------------------------------------------- /agent/bandwidth/ql_suss_queues.ksh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # vi: sw=4 ts=4: 3 | # 4 | # --------------------------------------------------------------------------- 5 | # Copyright (c) 2013-2015 AT&T Intellectual Property 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at: 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # --------------------------------------------------------------------------- 19 | # 20 | 21 | # ----------------------------------------------------------------------------------------------------------------- 22 | # Mnemonic: ql_suss_queues.ksh 23 | # Abstract: Dumps several 'tables' from the ovs database and builds a 24 | # summary of queue information. 25 | # Author: E. Scott Daniels 26 | # Date: 08 September 2014 27 | # 28 | # Mods: 26 Dec 2013 - Added support for finding and printing queue priority and eliminated the 29 | # need for user to run under sudu (we'll detect that need and do it). 30 | # 08 Sep 2014 - Ported from the original quick and dirty script (suss_ovs_queues) to make 31 | # it usable by the tegu agents in a q-lite environment. 32 | # 10 Nov 2014 - Added connect timeout to ssh calls 33 | # 28 Jan 2015 - Changes to eliminate uneeded ssh call if -h parm is for this host or localhost 34 | # ----------------------------------------------------------------------------------------------------------------- 35 | 36 | 37 | if (( $( id -u ) != 0 )) 38 | then 39 | sudo="sudo" 40 | fi 41 | 42 | ssh_opts="-o ConnectTimeout=2 -o StrictHostKeyChecking=no -o PreferredAuthentications=publickey" 43 | ssh="" # if -h given, this gets populated with the ssh command needed to run this on the remote 44 | 45 | backlevel_ovs=0 # assume modren ovs (1.10+) 46 | bridge="" 47 | show_headers=1 48 | show_units=1 49 | 50 | while [[ $1 == "-"* ]] 51 | do 52 | case $1 in 53 | -b) backlevel_ovs=1;; 54 | -B) show_headers=0; bridge=$2; shift;; 55 | -h) 56 | if [[ $2 != $(hostname) && $2 != "localhost" ]] 57 | then 58 | ssh="ssh -n $ssh_opts $2" # CAUTION: this MUST have -n since we don't redirect stdin to ssh 59 | fi 60 | shift 61 | ;; 62 | 63 | -u) show_units=0;; 64 | 65 | -\?) usage; 66 | exit;; 67 | esac 68 | 69 | shift 70 | done 71 | 72 | # we make a blind assumption that data is presented in the order requested by the --column flag 73 | # grrr.... bleeding ovs-vsctl 1.4.x is broken and doesn't recognise --column even though the man page says otherwise. 74 | ( 75 | if (( ! backlevel_ovs )) 76 | then 77 | $ssh $sudo ovs-vsctl --data=bare --column=name,_uuid,port list Bridge $bridge | sed 's/^/BRIDGE: /' 78 | $ssh $sudo ovs-vsctl --data=bare --column=name,_uuid,qos list Port | sed 's/^/PORT: /' 79 | $ssh $sudo ovs-vsctl --data=bare --column=_uuid,queues,other_config list QoS | sed 's/^/QOS: /' 80 | else 81 | 82 | # turning off columns we can only hope that _uuid is always output first (another claim by the man page, but we will see) 83 | $ssh $sudo ovs-vsctl --data=bare list Bridge $bridge | sed 's/^/BRIDGE: /' 84 | $ssh $sudo ovs-vsctl --data=bare list Port | sed 's/^/PORT: /' 85 | $ssh $sudo ovs-vsctl --data=bare list QoS | sed 's/^/QOS: /' 86 | $ssh $sudo ovs-vsctl --data=bare list Queue | sed 's/^/QUEUE: /' 87 | fi 88 | ) | awk \ 89 | -v show_units=$show_units \ 90 | -v show_headers=$show_headers \ 91 | ' 92 | BEGIN { seen_idx = 0; } 93 | NF < 4 { next; } 94 | 95 | /^BRIDGE: name/ { bname = $NF; seen[seen_idx++] = bname; next; } 96 | /^BRIDGE: ports/ { 97 | pidx[bname] = 0; 98 | for( i = 4; i <= NF; i++ ) 99 | { 100 | ports[bname,pidx[bname]] = $(i); 101 | pidx[bname]++; 102 | } 103 | next; 104 | } 105 | 106 | 107 | /^PORT: _uuid/ { puname = $NF; next; } # CAUTION -- uuid is (should) always be printed first 108 | /^PORT: name/ { pname = $NF; u2pname[puname] = pname; next; } # map the port uuid to human name 109 | /^PORT: qos/ { p2qos[puname] = $NF; next; } # map port to the qos entry 110 | 111 | /^QOS: _uuid/ { qoname = $NF; next; } 112 | /^QOS: other_config/ { 113 | for( i = 4; i <= NF; i++ ) 114 | { 115 | if( split( $(i), a, "=" ) == 2 ) 116 | qos_cfg[qoname,a[1]] = a[2] 117 | } 118 | next; 119 | } 120 | /^QOS: queues/ { 121 | for( i = 4; i <= NF; i++ ) 122 | { 123 | maxqueue[qoname] = 0; 124 | if( split( $(i), a, "=" ) == 2 ) 125 | { 126 | qos_q[qoname,a[1]+0] = a[2] 127 | if( maxqueue[qoname] < a[1] + 0 ) 128 | maxqueue[qoname] = a[1] + 0; 129 | } 130 | } 131 | next; 132 | } 133 | 134 | /^QUEUE: _uuid/ { qname = $NF; next; } 135 | /^QUEUE: other_config/ { 136 | for( i = 4; i <= NF; i++ ) 137 | { 138 | if( split( $(i), a, "=" ) == 2 ) 139 | qcfg[qname,a[1]] = a[2] 140 | } 141 | next; 142 | } 143 | 144 | END { 145 | for( i = 0; i < seen_idx; i++ ) 146 | { 147 | if( show_headers ) 148 | printf( "%s%s\n", i > 0 ? "\n" : "", seen[i] ); 149 | bname = seen[i]; 150 | 151 | for( j = 0; j < pidx[bname]; j++ ) 152 | { 153 | pu = ports[bname,j]; # ports id 154 | qos = p2qos[pu]; 155 | if( qos != "" ) # qos entry that it maps to 156 | { 157 | printf( " %s\n", u2pname[pu] ); # human port name 158 | 159 | for( k = 0; k <= maxqueue[qos]; k++ ) 160 | { 161 | qid = qos_q[qos,k]; 162 | if( qid != "" ) 163 | { 164 | if( show_units ) 165 | printf( " Q%d: min:%9.3fMbit/s max:%9.3fMbit/s pri:%d\n", k, qcfg[qid,"min-rate"]/1000000, qcfg[qid,"max-rate"]/1000000, qcfg[qid,"priority"] ); 166 | else 167 | { 168 | printf( " Q%d: min: %9.3f max: %9.3f pri: %d\n", k, qcfg[qid,"min-rate"], qcfg[qid,"max-rate"], qcfg[qid,"priority"] ); 169 | } 170 | } 171 | } 172 | } 173 | } 174 | } 175 | } 176 | ' 177 | 178 | exit $? 179 | 180 | 181 | # sample ovs output 182 | #bridge: 183 | #name : s5 184 | #_uuid : d807cfc0-8cc6-41cb-ac1c-6eb1bd1b6f08 185 | #ports : 6b200e3a-cfa1-4168-9510-879ee789bc0c 929dc121-d271-4657-8c9a-278712742589 9cb5e906-02d3-4819-9ece-6c8e949a857d c32ec7a5-eb4b-4484-86e5-6ea7f527b969 186 | # 187 | # 188 | #port: 189 | #name : s2-eth2 190 | #_uuid : 4a301fb0-df46-4739-8b53-b1f4a46f927c 191 | #qos : 414f8f52-3632-4028-a104-78a364bcb0c9 192 | # 193 | # 194 | #qos 195 | #_uuid : 7211e540-52c1-494f-9cd2-4e90a3307390 196 | #other_config : max-rate=1000000000 197 | #queues : 0=cc54fd8c-ad64-43a3-88dd-d01f1fac1c4b 1=9e59eafe-3115-4a73-9340-836b02e632f0 2=d983a9cb-7802-4765-a053-689a55bce270 198 | # 199 | #_uuid : c56ac7c0-8f2e-4f26-8ebf-9a1a985eca2d 200 | #other_config : max-rate=1000 min-rate=100 201 | -------------------------------------------------------------------------------- /agent/mirror/tegu_del_mirror.ksh: -------------------------------------------------------------------------------- 1 | #!/bin/ksh 2 | # vi: sw=4 ts=4: 3 | # 4 | # --------------------------------------------------------------------------- 5 | # Copyright (c) 2013-2015 AT&T Intellectual Property 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at: 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # --------------------------------------------------------------------------- 19 | 20 | # 21 | # Name: tegu_del_mirror 22 | # Usage: tegu_del_mirror [-o] [-v] 23 | # Abstract: This script deletes a mirror, named by , from openvswitch. 24 | # 25 | # The only currently valid option is -oflowmod, to delete a flowmod based mirror. 26 | # 27 | # Author: Robert Eby 28 | # Date: 04 February 2015 29 | # 30 | # Mods: 04 Feb 2015 - created 31 | # 11 Feb 2015 - remove temp file 32 | # 25 Jun 2015 - Corrected PATH. 33 | # 15 Sep 2015 - Remove extra copyright 34 | # 19 Oct 2015 - Allow delete of mirrors from bridges other than br-int 35 | # 15 Nov 2015 - Fixed rather bad bug introduced w/last change 36 | # 23 Nov 2015 - Add -oflowmod option processing 37 | # 18 Jan 2016 - Hardened logic so that we don't inadvertently delete all flows 38 | # 19 Jan 2016 - Log if a null flow is found when deleting flows 39 | # 40 | 41 | function logit 42 | { 43 | echo "$(date '+%s %Y/%m/%d %H:%M:%S') $argv0: $@" >&2 44 | } 45 | 46 | function findbridge 47 | { 48 | ovs_sp2uuid -a | awk -v uuid=$1 ' 49 | /^switch/ { br = $4 } 50 | /^port/ && $2 == uuid { print br }' 51 | } 52 | 53 | function option_set 54 | { 55 | echo $options | tr ' ' '\012' | grep $1 > /dev/null 56 | return $? 57 | } 58 | 59 | function usage 60 | { 61 | echo "usage: tegu_del_mirror [-o] [-v] name" >&2 62 | } 63 | 64 | argv0=${0##*/} 65 | PATH=$PATH:/sbin:/usr/bin:/bin # must pick up agent augmented path 66 | echo=: 67 | options= 68 | while [[ "$1" == -* ]] 69 | do 70 | if [[ "$1" == "-v" ]] 71 | then 72 | echo=echo 73 | shift 74 | elif [[ "$1" == -o* ]] 75 | then 76 | options=`echo $1 | sed -e 's/^-o//' -e 's/,/ /g'` 77 | shift 78 | else 79 | usage 80 | exit 1 81 | fi 82 | done 83 | 84 | if [ $# != 1 ] 85 | then 86 | usage 87 | exit 1 88 | fi 89 | if [ ! -x /usr/bin/ovs-vsctl ] 90 | then 91 | echo "tegu_del_mirror: ovs-vsctl is not installed or not executable." >&2 92 | exit 2 93 | fi 94 | 95 | sudo=sudo 96 | [ "`id -u`" == 0 ] && sudo= 97 | 98 | mirrorname=$1 99 | 100 | # Special code to handle flowmod-ed mirror 101 | if option_set flowmod 102 | then 103 | # Find bridge with the GRE port 104 | $echo $sudo ovs-vsctl list port gre-$mirrorname 105 | $sudo ovs-vsctl list port gre-$mirrorname > /tmp/x$$ && { 106 | grep _uuid < /tmp/x$$ | sed 's/.*://' > /tmp/m$$ 107 | rm /tmp/x$$ 108 | bridgename=$(findbridge $(cat /tmp/m$$)) 109 | 110 | # Find $GREPORT 111 | GREPORT=$(ovs_sp2uuid -a | grep gre-$mirrorname | cut -d' ' -f3) 112 | 113 | # Remove all flows with cookie=0xfaad from bridge that have actions=output:$GREPORT 114 | $sudo ovs-ofctl dump-flows $bridgename | grep "cookie=0xfaad.*output:$GREPORT," > /tmp/tdm.$$ 115 | for flow in $(sed -e 's/.*priority=100,//' -e 's/ actions=.*//' &2 124 | fi 125 | done 126 | rm -f /tmp/tdm.$$ /tmp/m$$ 127 | 128 | # Remove the GRE port 129 | $echo $sudo ovs-vsctl del-port $bridgename gre-$mirrorname 130 | $sudo ovs-vsctl del-port $bridgename gre-$mirrorname 131 | 132 | echo Mirror $mirrorname removed from bridge $bridgename. 133 | exit 0 134 | } 135 | else 136 | $echo $sudo ovs-vsctl get mirror "$mirrorname" output_port _uuid 137 | $sudo ovs-vsctl get mirror "$mirrorname" output_port _uuid > /tmp/m$$ && { 138 | # get output_port UUID 139 | uuid=`sed -n 1p /tmp/m$$` 140 | bridgename=$(findbridge $uuid) 141 | 142 | # get name from uuid 143 | $echo $sudo ovs-vsctl list port $uuid 144 | pname=`$sudo ovs-vsctl list port $uuid | grep name | tr -d '" ' | cut -d: -f2` 145 | # if it is a GRE port, with the right name, remove port 146 | case "$pname" in 147 | gre-$mirrorname) 148 | $echo $sudo ovs-vsctl del-port $bridgename $pname 149 | $sudo ovs-vsctl del-port $bridgename $pname 150 | ;; 151 | esac 152 | 153 | # get mirror UUID 154 | uuid=`sed -n 2p /tmp/m$$` 155 | $echo $sudo ovs-vsctl remove bridge $bridgename mirrors $uuid 156 | $sudo ovs-vsctl remove bridge $bridgename mirrors $uuid 157 | rm -f /tmp/m$$ 158 | 159 | echo Mirror $mirrorname removed from bridge $bridgename. 160 | exit 0 161 | } 162 | fi 163 | 164 | echo "tegu_del_mirror: mirror $mirrorname does not exist." >&2 165 | rm -f /tmp/m$$ 166 | exit 3 167 | -------------------------------------------------------------------------------- /const.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | /* 21 | Mnemonic: const.go 22 | Absrract: These are constants that are shared by all packages (gizmos, managers 23 | and main). There are likely to be very few of them. 24 | Date: 18 March 2014 25 | Author: E. Scott Daniels 26 | */ 27 | 28 | 29 | package tegu 30 | 31 | const ( 32 | SWFL_VISITED int = 0x01 // switch was visited during shortest path search 33 | ) 34 | -------------------------------------------------------------------------------- /doc/rjprt.1: -------------------------------------------------------------------------------- 1 | .\" 2 | .\" --------------------------------------------------------------------------- 3 | .\" Copyright (c) 2013-2015 AT&T Intellectual Property 4 | .\" 5 | .\" Licensed under the Apache License, Version 2.0 (the "License"); 6 | .\" you may not use this file except in compliance with the License. 7 | .\" You may obtain a copy of the License at: 8 | .\" 9 | .\" http://www.apache.org/licenses/LICENSE-2.0 10 | .\" 11 | .\" Unless required by applicable law or agreed to in writing, software 12 | .\" distributed under the License is distributed on an "AS IS" BASIS, 13 | .\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | .\" See the License for the specific language governing permissions and 15 | .\" limitations under the License. 16 | .\" --------------------------------------------------------------------------- 17 | .\" 18 | 19 | .\" 20 | .\" rjprt Manual Page 21 | .\" 22 | .\" Date: 14 Jun 2015 23 | .\" Author: E. Scott Daniels 24 | .\" Robert Eby 25 | .\" 26 | .\" Mods: 14 Jun 2015 - Created 27 | .\" 28 | .TH RJPRT 1 "Tegu Manual" 29 | .CM 4 30 | .SH NAME 31 | rjprt \- request and pretty-print JSON output from an HTTP server 32 | .SH SYNOPSIS 33 | \fBrjprt\fP [\fB-a token\fP] [\fB-D data-string\fP] [\fB-d\fP] [\fB-h\fP] [\fB-j\fP] [\fB-J\fP] [\fB-l dot-string\fP] [\fB-m method\fP] [\fB-r root-string\fP] [\fB-T\fP] [\fB-v\fP] \fB-t target-url\fP 34 | 35 | .SH DESCRIPTION 36 | \fIrjprt(1)\fR is a companion program used by tegu_req(1) to make HTTP requests to Tegu, 37 | and to format the JSON output that is returned. 38 | If \fItegu_req\fP is moved to another machine from the one that Tegu is 39 | installed on, this executable should also be moved and should be placed in 40 | the user's $PATH. 41 | .SH COMMAND LINE OPTIONS 42 | \fIrjprt\fR interprets the following options: 43 | .\" ========== 44 | .TP 8 45 | .B \-a token 46 | Causes an authorization token to be passed to Tegu using the \fBX-Auth-Tegu\fP header. 47 | .\" ========== 48 | .TP 8 49 | .B \-D data-string 50 | Specify the data to be used in the content body of a POST or DELETE request. 51 | If this option is not specified, then the data is read from standard input. 52 | .\" ========== 53 | .TP 8 54 | .B \-d 55 | Causes JSON output from Tegu to be formatted in a dotted hierarchical style. 56 | The default is to display the output in a indented, nested style (but see also -j below). 57 | .\" ========== 58 | .TP 8 59 | .B \-h 60 | Causes HTTP response headers to be printed. 61 | .\" ========== 62 | .TP 8 63 | .B \-j 64 | Causes JSON output from Tegu to be sent directly to the output (but see also -d above). 65 | .\" ========== 66 | .TP 8 67 | .B \-J 68 | Causes the Content-type for data sent to Tegu to be set to \fIapplication/json\fP. 69 | The default is \fItext\fP. 70 | .\" ========== 71 | .TP 8 72 | .B \-l dot-string 73 | Looks for and prints the specific \fIdot-string\fP in the dotted hierarchical output. 74 | If not found, an error is printed. 75 | Use of this option triggers the \fI-d\fP option. 76 | .TP 8 77 | .B \-m method 78 | Specifies the method (GET/POST/DELETE) to be used for the request to Tegu. 79 | The default is GET. 80 | .TP 8 81 | .B \-r name 82 | Allow specification of a "root" name for the JSON output. 83 | The default root name is the empty string. 84 | .TP 8 85 | .B \-T 86 | Causes \fIrjprt\fP to verify the server's identity when making secure TLS (HTTPS) requests to Tegu. 87 | The default behavior is to not check the servers identity. 88 | .TP 8 89 | .B \-v 90 | Causes \fIrjprt\fP to echo the target URL that will be used on standard error. 91 | .TP 8 92 | .B \-t target-url 93 | The target-url to request. 94 | This option is required. 95 | 96 | .SH SEE ALSO 97 | tegu_req(1), tegu.cfg(5), tegu(8) 98 | -------------------------------------------------------------------------------- /gizmos/fence.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: fence 24 | Abstract: Manages a current capacity and max/min values to keep something 25 | within limits. 26 | Date: 25 June 2014 27 | Author: E. Scott Daniels 28 | 29 | */ 30 | 31 | package gizmos 32 | 33 | import ( 34 | "fmt" 35 | ) 36 | 37 | // -------------------------------------------------------------------------------------- 38 | /* 39 | defines a host 40 | */ 41 | type Fence struct { 42 | Name *string // associated ID/name; available from outside for convenience 43 | max_cap int64 // max amount allowed to be contained 44 | min_cap int64 // min amount allowed to be contained 45 | value int64 // current capacity 46 | } 47 | 48 | /* 49 | Creates a fence with given max/min capacities and an intial value. 50 | */ 51 | func Mk_fence( name *string, max int64, min int64, init_val int64 ) ( f *Fence ) { 52 | 53 | f = &Fence { 54 | Name: name, 55 | max_cap: max, 56 | min_cap: min, 57 | value: init_val, 58 | } 59 | 60 | return 61 | } 62 | 63 | /* 64 | Tests current setting to see if adding c takes the value beyond either limit (c 65 | may be negative). Returns true if c can be added to the current value without 66 | busting the limit. 67 | */ 68 | func (f *Fence ) Has_capacity( c int64 ) ( bool ) { 69 | if c + f.value <= f.max_cap && c + f.value >= f.min_cap { 70 | return true 71 | } 72 | 73 | return false 74 | } 75 | 76 | /* 77 | Blindly adds the capacity c to the current value and clips if the 78 | new value exceeds a limit. 79 | */ 80 | func (f *Fence ) Inc_used( c int64 ) { 81 | f.value += c 82 | if f.value > f.max_cap { 83 | obj_sheep.Baa( 1, "WRN: clipping fence cap: max=%d cvalue=%d inc=%d tot=%d", f.max_cap, f.value, c, c+f.value ) // suggests something is wrong since it should not reach here if over 84 | f.value = f.max_cap 85 | } else { 86 | if f.value <= f.min_cap { 87 | f.value = f.min_cap 88 | } 89 | } 90 | } 91 | 92 | /* 93 | Checks to see if capacity can be added to the current value without 94 | violating a capacity limit. If it can be, then the value is added, else 95 | it is not and false is returned. 96 | */ 97 | func (f *Fence ) Inc_if_room( c int64 ) ( bool ) { 98 | if f.Has_capacity( c ) { 99 | f.value += c 100 | return true 101 | } 102 | 103 | return false 104 | } 105 | 106 | /* 107 | Returns the current value. 108 | */ 109 | func (f *Fence ) Get_value() ( int64 ) { 110 | return f.value 111 | } 112 | 113 | /* 114 | Sets the value to c and clips if it's beyond a limit. 115 | The actual value set is returned. 116 | */ 117 | func (f *Fence ) Set_value( c int64 ) ( int64 ) { 118 | f.value = 0 119 | f.Inc_used( c ) 120 | 121 | return f.value 122 | } 123 | 124 | /* 125 | Accepts a requested additional capacity and returns the total capacity allowed (have) 126 | by the fence and the value that is needed (current allocation + additional amount). 127 | */ 128 | func (f *Fence) Get_have_need( addtl_cap int64 ) ( have int64, need int64 ) { 129 | if addtl_cap < 0 { 130 | return f.min_cap, f.value + addtl_cap 131 | } 132 | 133 | return f.max_cap, f.value + addtl_cap 134 | } 135 | 136 | /* 137 | Returns the max limit. 138 | */ 139 | func (f *Fence ) Get_limit_max( ) ( int64 ) { 140 | return f.max_cap 141 | } 142 | 143 | /* 144 | Returns the min limit. 145 | */ 146 | func (f *Fence ) Get_limit_min( ) ( int64 ) { 147 | return f.min_cap 148 | } 149 | 150 | /* 151 | Returns the max and min capacity limits. 152 | */ 153 | func (f *Fence ) Get_limits( ) ( max int64, min int64 ) { 154 | return f.max_cap, f.min_cap 155 | } 156 | 157 | /* 158 | Create a copy of the fence. If a capacity value is passed in the function 159 | will check the current min/max and if less than 100 assume they are a 160 | percentage and compute the actual min/max using the percentage of the 161 | capacity. If capacity is 0, then no check is made. 162 | */ 163 | func (f *Fence) Clone( capacity int64 ) ( *Fence ) { 164 | nf := Mk_fence( f.Name, f.max_cap, f.min_cap, f.value ) 165 | if capacity > 0 { 166 | if nf.max_cap < 101 { 167 | nf.max_cap = (capacity/100) * nf.max_cap // assume max_cap is a percentage, so adjust 168 | } 169 | if nf.min_cap < 101 { 170 | nf.min_cap = (capacity/100) * nf.min_cap // assume max_cap is a percentage, so adjust 171 | } 172 | } 173 | 174 | return nf 175 | } 176 | 177 | /* 178 | Creates a new object and copies the information replacing the name in the new 179 | object with the name passed in. 180 | */ 181 | func (f *Fence) Copy( new_name *string ) ( *Fence ) { 182 | return Mk_fence( new_name, f.max_cap, f.min_cap, f.value ) 183 | } 184 | 185 | 186 | /* 187 | Jsonise the whole object. 188 | */ 189 | func (f *Fence) To_json( ) ( s string ) { 190 | 191 | if f == nil { 192 | s = `` 193 | return 194 | } 195 | 196 | s = fmt.Sprintf( `{ "name": %q, "max": %d, "min": %d, "value": %d }`, *f.Name, f.max_cap, f.min_cap, f.value ) 197 | 198 | return 199 | } 200 | -------------------------------------------------------------------------------- /gizmos/flowmod.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | ------------------------------------------------------------------------------------------------ 23 | Mnemonic: flowmod 24 | Abstract: Manages flowmod related structures for communicating with the agent. 25 | Date: 09 May 2014 26 | Authors: E. Scott Daniels, Matti Hiltnuen, Kaustubh Joshi 27 | 28 | Modifed: 29 | ------------------------------------------------------------------------------------------------ 30 | */ 31 | 32 | package gizmos 33 | 34 | import ( 35 | "encoding/json" 36 | ) 37 | 38 | 39 | // these values are all public so that we can use the json marshal() function to build the json 40 | type fmod_match struct { 41 | Src_mac string 42 | Dest_mac string 43 | Dscp int 44 | } 45 | 46 | type fmod_action struct { 47 | Dscp int 48 | Queue int 49 | } 50 | 51 | type fmod struct { 52 | Priority int 53 | Timeout int 54 | Cookie int 55 | Swname string // switch 56 | 57 | Match *fmod_match 58 | Action *fmod_action 59 | } 60 | 61 | /* 62 | Create a generic struct from basic data 63 | */ 64 | func Mk_flow_mod( priority int, timeout int, cookie int, swname string ) ( fm *fmod ) { 65 | fm = &fmod{ 66 | Priority: priority, 67 | Timeout: timeout, 68 | Cookie: cookie, 69 | Swname: swname, 70 | } 71 | 72 | fm.Match = &fmod_match{} 73 | fm.Action = &fmod_action{} 74 | 75 | return 76 | } 77 | 78 | /* 79 | Set one or both values in the action. If either value is less than zero 80 | then the cooresponding value in the action is unchanged. 81 | */ 82 | func (fm *fmod) Set_action( dscp int, queue int ) { 83 | if fm != nil { 84 | if dscp >= 0 { 85 | fm.Action.Dscp = dscp 86 | } 87 | if queue >= 0 { 88 | fm.Action.Queue = queue 89 | } 90 | } 91 | } 92 | 93 | /* 94 | Set values in the match. If any values are < 0, or an empty string, the 95 | value is not changed. 96 | */ 97 | func (fm *fmod) Set_match( src_mac string, dest_mac string, dscp int ) { 98 | if fm != nil { 99 | if dscp >= 0 { 100 | fm.Match.Dscp = dscp 101 | } 102 | if src_mac != "" { 103 | fm.Match.Src_mac = src_mac 104 | } 105 | if dest_mac != "" { 106 | fm.Match.Dest_mac = dest_mac 107 | } 108 | } 109 | } 110 | 111 | func (fm *fmod) To_json( ) ( jbytes []byte, err error ) { 112 | jbytes, err = json.Marshal( fm ) 113 | 114 | return 115 | } 116 | -------------------------------------------------------------------------------- /gizmos/gizmos_lite_test.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: gizmos_lite_test 24 | Abstract: builds tests to test the lite things 25 | Date: 28 April 2014 26 | Author: E. Scott Daniels 27 | 28 | */ 29 | 30 | package gizmos_test 31 | 32 | import ( 33 | //"bufio" 34 | //"encoding/json" 35 | //"flag" 36 | "fmt" 37 | //"io/ioutil" 38 | //"html" 39 | //"net/http" 40 | "os" 41 | //"strings" 42 | //"time" 43 | "testing" 44 | 45 | "github.com/att/tegu/gizmos" 46 | ) 47 | 48 | const ( 49 | time_12am int64 = 1357016400 // various timestamps for setting windows 50 | time_1am int64 = 1357020000 51 | time_5am int64 = 1357034400 52 | time_12pm int64 = 1357059600 53 | max_cap int64 = 100000 54 | ) 55 | 56 | /* 57 | Test the ability to load links from a file 58 | */ 59 | func TestLoadLinks( t *testing.T ) { // must use bloody camel case to be recognised by go testing 60 | 61 | 62 | fmt.Fprintf( os.Stderr, "-------- q-lite tests ---------------\n" ) 63 | 64 | links, err := gizmos.Read_json_links( "static_links.json" ) 65 | if err == nil { 66 | fmt.Fprintf( os.Stdout, "Successful %d\n", len( links ) ) 67 | for i := range links { 68 | fmt.Fprintf( os.Stdout, "link: %s/%d-%s/%d\n", links[i].Src_switch, links[i].Src_port, links[i].Dst_switch, links[i].Dst_port ) 69 | } 70 | } else { 71 | fmt.Fprintf( os.Stdout, "failed to read links: %s [FAIL]\n", err ) 72 | t.Fail() 73 | } 74 | 75 | fmt.Fprintf( os.Stderr, "\n" ) 76 | } 77 | -------------------------------------------------------------------------------- /gizmos/gizmos_net_test.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: gizmos_net_test 24 | Abstract: Builds a test network and runs some of the path finding functions to verify 25 | Date: 10 June 2014 26 | Author: E. Scott Daniels 27 | 28 | */ 29 | 30 | package gizmos_test 31 | 32 | import ( 33 | //"bufio" 34 | //"encoding/json" 35 | //"flag" 36 | "fmt" 37 | //"io/ioutil" 38 | //"html" 39 | //"net/http" 40 | "os" 41 | //"strings" 42 | //"time" 43 | "testing" 44 | 45 | "github.com/att/tegu/gizmos" 46 | ) 47 | 48 | const ( 49 | ) 50 | 51 | /* 52 | Test some network pathfinding. Reads a topo from the static json file test_net.json and builds 53 | a network of hosts and links, then attempts to find all paths between them using the switch 54 | find all functions. 55 | */ 56 | func TestNet( t *testing.T ) { // must use bloody camel case to be recognised by go testing 57 | 58 | var ( 59 | fsw *gizmos.Switch 60 | sw_list map[string]*gizmos.Switch 61 | ) 62 | 63 | sw_list = make( map[string]*gizmos.Switch ) 64 | fmt.Fprintf( os.Stderr, "\n------------- net test starts -----------------\n" ) 65 | links, err := gizmos.Read_json_links( "test_net.json" ) 66 | if err == nil { 67 | fmt.Fprintf( os.Stderr, "read %d links from the file\n", len( links ) ) 68 | } else { 69 | fmt.Fprintf( os.Stderr, "failed to read links: %s [FAIL]\n", err ) 70 | t.Fail() 71 | return 72 | } 73 | 74 | last := "" 75 | fsw = nil 76 | for i := range links { // parse all links returned from the controller 77 | ssw := sw_list[links[i].Src_switch] 78 | if ssw == nil { 79 | ssw = gizmos.Mk_switch( &links[i].Src_switch ) // source switch 80 | sw_list[links[i].Src_switch] = ssw 81 | } 82 | 83 | dsw := sw_list[links[i].Dst_switch] 84 | if dsw == nil { 85 | dsw = gizmos.Mk_switch( &links[i].Dst_switch ) // dest switch 86 | sw_list[links[i].Dst_switch] = dsw 87 | } 88 | 89 | l := gizmos.Mk_link( ssw.Get_id(), dsw.Get_id(), 100000000, 95, nil ); // link in forward direction 90 | l.Set_forward( dsw ) 91 | l.Set_backward( ssw ) 92 | ssw.Add_link( l ) 93 | 94 | l = gizmos.Mk_link( dsw.Get_id(), ssw.Get_id(), 100000000, 95, nil ); // link in backward direction 95 | l.Set_forward( ssw ) 96 | l.Set_backward( dsw ) 97 | dsw.Add_link( l ) 98 | 99 | mac := fmt.Sprintf( "00:00:00:00:00:%02d", i ) 100 | ip := fmt.Sprintf( "10.0.0.%02d", i ) 101 | h := gizmos.Mk_host( mac, ip, "" ) 102 | h.Add_switch( ssw, i ) // add a host to each src switch 103 | vmname := "foobar-name" 104 | ssw.Add_host( &ip, &vmname, i+200 ) 105 | fmt.Fprintf( os.Stderr, "adding host: %s\n", ip ) 106 | 107 | if fsw == nil { // save first switch to use as start of search 108 | fsw = ssw 109 | } 110 | 111 | mac = fmt.Sprintf( "%02d:00:00:00:00:00", i ) 112 | ip = fmt.Sprintf( "10.0.0.1%02d", i ) 113 | h = gizmos.Mk_host( mac, ip, "" ) 114 | h.Add_switch( dsw, i ) // add a host to each dest switch 115 | vmname2 := "foobar-name2" 116 | dsw.Add_host( &ip, &vmname2, i+200 ) 117 | 118 | fmt.Fprintf( os.Stderr, "adding host: %s\n", ip ) 119 | last = ip 120 | } 121 | 122 | fmt.Fprintf( os.Stderr, ">>> searching for: %s\n", last ); 123 | usrname := "username" 124 | fsw.All_paths_to( &last, 0, 0, 100, &usrname, 95 ) 125 | } 126 | 127 | -------------------------------------------------------------------------------- /gizmos/gizmos_pt_test.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: gizmos_pledge_pt_test 24 | Abstract: test some of the pasthrough pledge functions. 25 | Date: 26 March 2015 26 | Author: E. Scott Daniels 27 | 28 | */ 29 | 30 | package gizmos_test 31 | 32 | import ( 33 | "fmt" 34 | "os" 35 | "testing" 36 | "time" 37 | 38 | "github.com/att/tegu/gizmos" 39 | ) 40 | 41 | const ( 42 | ) 43 | 44 | // ---- support ----------------------------------------------------------------------- 45 | 46 | 47 | // --- tests -------------------------------------------------------------------------- 48 | func TestPass_pledge( t *testing.T ) { 49 | 50 | fmt.Fprintf( os.Stderr, "\n------- make passthrou pledge -----------\n" ) 51 | host := "host" 52 | port := "7890" 53 | commence := time.Now().Unix() + 3600 54 | expiry := int64( commence + 45 ) 55 | id := "res-test-pass-pledge" 56 | ukey := "my-cookie" 57 | 58 | ppt1, err := gizmos.Mk_pass_pledge( &host, &port, commence, expiry, &id, &ukey ) 59 | if err != nil { 60 | fmt.Fprintf( os.Stderr, "cannot make pass pledge; all other passthrough tests aborted: %s [FAIL]\n", err ) 61 | t.Fail() 62 | return 63 | } 64 | fmt.Fprintf( os.Stderr, "mk successful\n" ); 65 | 66 | pptc := ppt1.Clone( "cloned" ) 67 | if pptc == nil { 68 | fmt.Fprintf( os.Stderr, "cannot clone pass pledge; all other passthrough tests aborted [FAIL]\n" ) 69 | t.Fail() 70 | return 71 | } 72 | fmt.Fprintf( os.Stderr, "clone successful\n" ); 73 | 74 | host2 := "host2" 75 | port2 := "7890" 76 | id2 := "res-test-pass-pledge2" 77 | ukey2 := "my-cookie" 78 | ppt2, err := gizmos.Mk_pass_pledge( &host2, &port2, commence, expiry, &id2, &ukey2 ) 79 | if err != nil { 80 | fmt.Fprintf( os.Stderr, "cannot make second pass pledge; all other passthrough tests aborted: %s [FAIL]\n", err ) 81 | t.Fail() 82 | return 83 | } 84 | 85 | gp := gizmos.Pledge( pptc ) // must convert to a generic pledge so we can take address off next 86 | if ppt1.Equals( &gp ) { 87 | fmt.Fprintf( os.Stderr, "clone reports equal [OK]\n" ) 88 | } else { 89 | fmt.Fprintf( os.Stderr, "clone reports !equal [FAIL]\n" ) 90 | } 91 | 92 | gp = gizmos.Pledge( ppt2 ) // must convert to a generic pledge so we can take address off next 93 | if ppt1.Equals( &gp ) { 94 | fmt.Fprintf( os.Stderr, "second pledge reports equal [FAIL]\n" ) 95 | } else { 96 | fmt.Fprintf( os.Stderr, "second pledge reports !equal [OK]\n" ) 97 | } 98 | 99 | 100 | fmt.Fprintf( os.Stderr, "json: %s\n", ppt1.To_json() ) 101 | fmt.Fprintf( os.Stderr, "string: %s\n", ppt1 ) 102 | fmt.Fprintf( os.Stderr, "chkpt: %s\n", ppt1.To_chkpt() ) 103 | 104 | } 105 | -------------------------------------------------------------------------------- /gizmos/gizmos_test.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: gizmos_test 24 | Abstract: test some of the gizmos that can be tested this way 25 | Date: 26 March 2015 26 | Author: E. Scott Daniels 27 | 28 | */ 29 | 30 | package gizmos_test 31 | 32 | import ( 33 | "fmt" 34 | "os" 35 | "testing" 36 | 37 | "github.com/att/tegu/gizmos" 38 | ) 39 | 40 | const ( 41 | ) 42 | 43 | // ---- support ----------------------------------------------------------------------- 44 | func split( s string, ename string, eport string ) int { 45 | n, p := gizmos.Split_port( &s ) 46 | state := "FAIL:" 47 | rc := 1 48 | if ename == *n && eport == *p { 49 | state = "OK:" 50 | rc = 0 51 | } 52 | fmt.Fprintf( os.Stderr, "%-6s %s --> n=(%s) p=(%s)\n", state, s, *n, *p ) 53 | 54 | return rc 55 | } 56 | 57 | // --- tests -------------------------------------------------------------------------- 58 | func TestSplitPort( t *testing.T ) { 59 | 60 | fmt.Fprintf( os.Stderr, "\n------- split port tests ----------------\n" ) 61 | overall_state := 0 62 | overall_state += split( "123.45.67.89", "123.45.67.89", "0" ) 63 | overall_state += split( "123.45.67.89:1234", "123.45.67.89", "1234" ) 64 | overall_state += split( "token/project/123.45.67.89:1234", "token/project/123.45.67.89", "1234" ) 65 | 66 | overall_state += split( "token/project/fe81::1", "token/project/fe81::1", "0" ) 67 | overall_state += split( "token/project/[fe81::1]", "token/project/fe81::1", "0" ) 68 | 69 | overall_state += split( "token/project/[fe81::1]:80", "token/project/fe81::1", "80" ) 70 | overall_state += split( "token/project/[1fff:0:a88:85a3::ac1f]:8001", "token/project/1fff:0:a88:85a3::ac1f", "8001" ) 71 | 72 | if overall_state > 0 { 73 | t.Fail() 74 | } 75 | } 76 | 77 | func TestBracketAddress( t *testing.T ) { 78 | fmt.Fprintf( os.Stderr, "\n------- bracket address tests -----------\n" ) 79 | b := gizmos.Bracket_address( "foo/bar/123.45.67.89" ) 80 | fmt.Fprintf( os.Stderr, "%s\n", *b ) 81 | 82 | b = gizmos.Bracket_address( "foo/bar/fe81::1" ) 83 | fmt.Fprintf( os.Stderr, "%s\n", *b ) 84 | } 85 | 86 | func TestHasKey( t *testing.T ) { 87 | 88 | fails := false 89 | 90 | fmt.Fprintf( os.Stderr, "\n------- has key tests -------------------\n" ) 91 | m := make( map[string]string ) 92 | m["foo"] = "foo is here" 93 | m["bar"] = "bar is here" 94 | m["you"] = "you are here" 95 | 96 | state, list := gizmos.Map_has_all( m, "you foo bar" ) 97 | if state { 98 | fmt.Fprintf( os.Stderr, "OK: all expected were there\n" ) 99 | } else { 100 | fmt.Fprintf( os.Stderr, "FAIL: some reported missing and that is not expcted. missing list: %s\n", list ) 101 | fails = true 102 | } 103 | 104 | state, list = gizmos.Map_has_all( m, "goo boo you foo bar" ) 105 | if state { 106 | fmt.Fprintf( os.Stderr, "FAIL: all expected were there and list had things that were known to be missing\n" ) 107 | fails = true 108 | } else { 109 | fmt.Fprintf( os.Stderr, "OK: some reported missing as expected: %s\n", list ) 110 | } 111 | 112 | if fails { 113 | t.Fail() 114 | } 115 | } 116 | 117 | /* 118 | func TestPledgeWindowOverlap( t *testing.T ) { 119 | gizmos.Test_pwo( t ) 120 | } 121 | */ 122 | -------------------------------------------------------------------------------- /gizmos/gizmos_tools_test.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: gizmos_tools_test 24 | Abstract: Tesets the tools 25 | Date: 15 Jul 2014 26 | Author: E. Scott Daniels 27 | 28 | */ 29 | 30 | package gizmos_test 31 | 32 | import ( 33 | //"bufio" 34 | //"encoding/json" 35 | //"flag" 36 | "fmt" 37 | //"io/ioutil" 38 | //"html" 39 | //"net/http" 40 | "os" 41 | "strings" 42 | //"time" 43 | "testing" 44 | 45 | "github.com/att/tegu/gizmos" 46 | ) 47 | 48 | const ( 49 | ) 50 | 51 | /* 52 | */ 53 | func TestTools( t *testing.T ) { // must use bloody camel case to be recognised by go testing 54 | 55 | 56 | fmt.Fprintf( os.Stderr, "----- tools testing begins--------\n" ) 57 | s := "foo var1=value1 var2=val2 foo bar you" 58 | toks := strings.Split( s, " " ) 59 | m := gizmos.Mixtoks2map( toks[1:], "a b c d e f" ) 60 | 61 | for k, v := range m { 62 | fmt.Fprintf( os.Stderr, "%s = %s\n", k, *v ) 63 | } 64 | } 65 | 66 | func test_one_hasany( t *testing.T, kstr string, ui interface{}, expect bool ) ( int ) { 67 | ecount := 0 68 | toks := strings.Split( kstr, " " ) 69 | 70 | state := gizmos.Map_has_any( ui, toks ) // true if map has any key in the list 71 | if state == expect { 72 | fmt.Fprintf( os.Stderr, "[OK] expected %v state checking key list (tokenised): %s\n", state, kstr ) 73 | } else { 74 | fmt.Fprintf( os.Stderr, "[FAIL] unexpected %v state checking key list (tokenised): %s\n", state, kstr ) 75 | t.Fail() 76 | ecount++ 77 | } 78 | 79 | // test passing a string 80 | state = gizmos.Map_has_any( ui, kstr ) // true if map has any key in the list 81 | if state == expect { 82 | fmt.Fprintf( os.Stderr, "[OK] expected %v state checking key list by string: %s\n", state, kstr ) 83 | return 0 84 | } else { 85 | fmt.Fprintf( os.Stderr, "[FAIL] unexpected %v state checking key list by string: %s\n", state, kstr ) 86 | t.Fail() 87 | ecount++ 88 | } 89 | 90 | return ecount 91 | } 92 | 93 | func TestAnyKey( t *testing.T ) { 94 | fmt.Fprintf( os.Stderr, "\n------ key map testing ------\n" ) 95 | m := make( map[string]bool, 15 ) 96 | 97 | m["foo"] = true 98 | m["goo"] = false 99 | m["longer"] = false 100 | m["tegu_admin"] = false 101 | m["admin"] = false 102 | 103 | for k := range m { 104 | fmt.Fprintf( os.Stderr, "[INFO] key in the map: %s\n", k ) 105 | } 106 | 107 | errs := test_one_hasany( t, "foo bar now are you here", m, true ) 108 | errs += test_one_hasany( t, "tegu_admin tegu_mirror admin", m, true ) 109 | errs += test_one_hasany( t, "tegu_mirror tegu_bwr", m, false ) 110 | 111 | if errs == 0 { 112 | fmt.Fprintf( os.Stderr, "[OK] All key checks passed\n" ) 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /gizmos/host.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: host 24 | Abstract: manages a host in the network 25 | Date: 25 November 2013 26 | Author: E. Scott Daniels 27 | 28 | Note: If the network is split (not all switches are being controlled by 29 | floodlight, then a host might show multiple connections: one on the 30 | switch that it is truly connectted to, and one for each switch that 31 | has an 'entry point' (likely a link to an uncontrolled switch) for 32 | the host. At the moment, it does not appear that it is possible to 33 | map the IP address to the switch/port as the list of IPs and the list 34 | of attachment points seem not to be ordered. 35 | 36 | Mod: 29 Jun 2014 - Changes to support user link limits. 37 | 26 Mar 2015 - Added Get_address() function to return one address with 38 | favourtism if host has both addresses defined. 39 | */ 40 | 41 | package gizmos 42 | 43 | import ( 44 | //"bufio" 45 | "fmt" 46 | //"os" 47 | //"strings" 48 | //"time" 49 | ) 50 | 51 | // -------------------------------------------------------------------------------------- 52 | /* 53 | defines a host 54 | */ 55 | type Host struct { 56 | vmid *string // id given to host by virtulation manager (e.g. ostack) 57 | mac string 58 | ip4 string 59 | ip6 string 60 | conns []*Switch // the switches that it connects to (see note) 61 | ports []int // ports match with Switch entries 62 | cidx int 63 | } 64 | 65 | /* 66 | Create the object setting defaults and adding user supplied IP address strings. 67 | */ 68 | func Mk_host( mac string, ip4 string, ip6 string ) (h *Host) { 69 | 70 | h = &Host { 71 | mac: mac, 72 | ip4: ip4, 73 | ip6: ip6, 74 | cidx: 0, 75 | } 76 | 77 | h.conns = make( []*Switch, 5 ) 78 | h.ports = make( []int, 5 ) 79 | 80 | return 81 | } 82 | 83 | /* 84 | Destruction 85 | */ 86 | func ( h *Host ) Nuke() { 87 | 88 | if h == nil { 89 | return 90 | } 91 | 92 | h.conns = nil 93 | h.ports = nil 94 | } 95 | 96 | /* 97 | Adds the vmid to the host (usually not known at mk time, so it's not a part of the mk process. 98 | */ 99 | func (h *Host) Add_vmid( vmid *string ) { 100 | h.vmid = vmid 101 | } 102 | 103 | /* 104 | allows more switches to be added 105 | */ 106 | func (h *Host) Add_switch( sw *Switch, port int ) { 107 | var ( 108 | new_conns []*Switch 109 | new_ports []int 110 | ) 111 | 112 | if h == nil { 113 | return 114 | } 115 | 116 | if h.cidx >= len( h.conns ) { // out of room, extend and copy to new 117 | new_conns = make( []*Switch, h.cidx + 10 ) 118 | new_ports = make( []int, h.cidx + 10 ) 119 | for i := 0; i < h.cidx; i++ { 120 | new_conns[i] = h.conns[i] 121 | new_ports[i] = h.ports[i] 122 | } 123 | h.conns = new_conns 124 | h.ports = new_ports 125 | } 126 | 127 | h.conns[h.cidx] = sw; 128 | h.ports[h.cidx] = port 129 | h.cidx++ 130 | } 131 | 132 | /* 133 | Return the ith switch and associated port from the connections list 134 | Allows an owner of the object to iterate over the switches without 135 | having to have direct access to the lists. 136 | */ 137 | func (h *Host) Get_switch_port( i int ) ( s *Switch, p int ) { 138 | s = nil 139 | p = -1 140 | 141 | if h != nil && i < len( h.conns ) { 142 | s = h.conns[i] 143 | p = h.ports[i] 144 | } 145 | 146 | return 147 | } 148 | 149 | /* 150 | Return the switch ID of the ith connected switch. 151 | */ 152 | func( h *Host) Get_switch_id( i int ) ( *string ) { 153 | if h == nil || i >= len( h.conns ) { 154 | return nil 155 | } 156 | 157 | 158 | return h.conns[i].Get_id() 159 | } 160 | 161 | /* 162 | Returns the port the host is 'attached to' for the given switch. 163 | In a disjoint network attached might not be true, but it's the 164 | port that the switch should write traffic on destined for the host. 165 | */ 166 | func (h *Host) Get_port( s *Switch ) ( int ) { 167 | var p int 168 | 169 | if h == nil { 170 | return -1 171 | } 172 | 173 | for p = 0; p < h.cidx; p++ { 174 | if h.conns[p] == s { 175 | return h.ports[p] 176 | } 177 | } 178 | 179 | p = -1 180 | return p 181 | } 182 | 183 | /* 184 | Drives the callback function for each switch/port combination that we have in our list. 185 | Data is the user data that is passed in that the callback function may need to process. 186 | func (h *Host) Iterate_switch_port( data interface{}, cb func( *Switch, int, interface{} ) ) { 187 | for i := 0; i < h.cidx; i++ { 188 | cb( h.switch, h.port, data ) 189 | } 190 | } 191 | */ 192 | 193 | /* 194 | Return both IP address strings or nil 195 | */ 196 | func ( h *Host ) Get_addresses( ) ( ip4 *string, ip6 *string ) { 197 | if h == nil { 198 | return nil, nil 199 | } 200 | 201 | ip4 = &h.ip4 202 | ip6 = &h.ip6 203 | return 204 | } 205 | 206 | /* 207 | Return one of the IP addresses associated with the host. If both are defined the IPv6 addr 208 | is returned in favour of the IP v4 address if pref_v6 is true. 209 | */ 210 | func( h *Host ) Get_address( pref_v6 bool ) ( *string ) { 211 | if h == nil { 212 | return nil 213 | } 214 | 215 | if (h.ip6 != "" && pref_v6) || h.ip4 == "" { 216 | return &h.ip6 217 | } 218 | 219 | return &h.ip4 220 | } 221 | 222 | /* 223 | Return the number of connections. 224 | */ 225 | func ( h *Host ) Get_nconns( ) ( int ) { 226 | if h == nil { 227 | return 0 228 | } 229 | 230 | return h.cidx 231 | } 232 | 233 | /* 234 | Return a pointer to the string that has the mac address. 235 | */ 236 | func (h *Host) Get_mac( ) (s *string) { 237 | if h == nil { 238 | return nil 239 | } 240 | 241 | return &h.mac 242 | } 243 | 244 | /* 245 | Generate a string of the basic info 246 | Deprecated in favour of stringer interface method. 247 | */ 248 | func (h *Host) To_str( ) ( s string ) { 249 | return h.String() 250 | } 251 | 252 | /* 253 | Generate a string of the basic info 254 | */ 255 | func (h *Host) String( ) ( s string ) { 256 | if h == nil { 257 | return "--nil--" 258 | } 259 | 260 | s = fmt.Sprintf( "{ host: %s ", h.mac ) 261 | if h.ip4 != "" { 262 | s += fmt.Sprintf( "ip4: %s ", h.ip4 ) 263 | } 264 | if h.ip6 != "" { 265 | s += fmt.Sprintf( "ip6: %s ", h.ip6 ) 266 | } 267 | 268 | if h.cidx > 0 { 269 | s += fmt.Sprintf( " connections [ " ) 270 | for i := 0; i < h.cidx; i++ { 271 | if h.conns[i] != nil { 272 | id := h.conns[i].Get_id() 273 | if id != nil { 274 | s += fmt.Sprintf( "%s ", *id ) 275 | } 276 | } else { 277 | s += "==nil-connection== " 278 | } 279 | } 280 | s += "]" 281 | } 282 | 283 | return 284 | } 285 | 286 | /* 287 | Jsonise the whole object. 288 | */ 289 | func (h *Host) To_json( ) ( s string ) { 290 | var ( 291 | sep string = "" 292 | ) 293 | 294 | if h == nil { 295 | s = `{ "mac": "null-host" } ` 296 | return 297 | } 298 | 299 | if h.vmid != nil { 300 | s = fmt.Sprintf( `{ "vmid": %q, "mac": %q`, *h.vmid, h.mac ) 301 | } else { 302 | s = fmt.Sprintf( `{ "vmid": "missing", "mac": %q`, h.mac ) 303 | } 304 | 305 | if h.ip4 != "" { 306 | s += fmt.Sprintf( `, "ip4": %q`, h.ip4 ) 307 | } 308 | if h.ip6 != "" { 309 | s += fmt.Sprintf( `, "ip6": %q`, h.ip6 ) 310 | } 311 | 312 | if h.cidx > 0 { 313 | s += fmt.Sprintf( `, "connections": [ ` ) 314 | for i := 0; i < h.cidx; i++ { 315 | s += fmt.Sprintf( `%s%q`, sep, *(h.conns[i].Get_id()) ) 316 | sep = "," 317 | } 318 | s += "] " 319 | } 320 | 321 | if h.cidx > 0 { 322 | sep = "" 323 | s += fmt.Sprintf( `, "ports": [ ` ) 324 | for i := 0; i < h.cidx; i++ { 325 | s += fmt.Sprintf( "%s%d", sep, h.ports[i] ) 326 | sep = "," 327 | } 328 | s += "] " 329 | } 330 | 331 | s += "}" 332 | 333 | return 334 | } 335 | 336 | /* 337 | generate json output that describes each swtitch/port combination that this host has. 338 | */ 339 | func (h *Host) Ports2json( ) ( s string ) { 340 | var ( 341 | sep string = "" 342 | ) 343 | if h == nil { 344 | return `{ "mac": "null-host" }` 345 | } 346 | 347 | s = fmt.Sprintf( `{ "host": { "ip4": %q, "mac": %q, "conns": [`, h.ip4, h.mac ) 348 | for i := 0; i < h.cidx; i++ { 349 | if h.conns[i] != nil { 350 | sname := h.conns[i].Get_id() 351 | s += fmt.Sprintf( `%s { "switch": %q, "port": %d }`, sep, *sname, h.ports[i] ) 352 | sep = ","; 353 | } 354 | } 355 | 356 | s += fmt.Sprintf( `] } }` ) 357 | return 358 | } 359 | -------------------------------------------------------------------------------- /gizmos/init.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: init.go 24 | Abstract: package level initialisation and constants for the gizmos package 25 | Date: 18 March 2014 26 | Author: E. Scott Daniels 27 | 28 | Mods: 11 Jun 2014 : Added external level control for bleating, and changed the 29 | bleat id to gizmos. 30 | 24 Jun 2014 : Added new constants for steering pledges. 31 | 17 Feb 2015 : Added mirroring 32 | */ 33 | 34 | package gizmos 35 | 36 | 37 | import ( 38 | "os" 39 | "github.com/att/gopkgs/bleater" 40 | ) 41 | 42 | //import "github.com/att/tegu" 43 | 44 | // DANGER: do NOT change the order of these as the values end up hard coded in the checkpoint file 45 | // once datacache is implemented there is no danger, but until then bad things will happen 46 | // if the order is not preserved. Add new ones to the end! 47 | const ( 48 | PT_BANDWIDTH int = iota // pledge types 49 | PT_STEERING 50 | PT_MIRRORING 51 | PT_OWBANDWIDTH // one way bandwidth 52 | PT_PASSTHRU // passthrough dscp marking reservation 53 | ) 54 | 55 | var ( 56 | empty_str string = "" // these make &"" possible since that's not legal in go 57 | zero_str string = "0" 58 | 59 | obj_sheep *bleater.Bleater // sheep that objeects have reference to when needing to bleat 60 | ) 61 | 62 | /* 63 | Initialisation for the package; run once automatically at startup. 64 | */ 65 | func init( ) { 66 | obj_sheep = bleater.Mk_bleater( 0, os.Stderr ) // allocate our bleater 67 | obj_sheep.Set_prefix( "gizmos" ) 68 | } 69 | 70 | /* 71 | Returns the package's sheep so that the main can attach it to the 72 | master sheep and thus affect the volume of bleats from this package. 73 | */ 74 | func Get_sheep( ) ( *bleater.Bleater ) { 75 | return obj_sheep 76 | } 77 | 78 | /* 79 | Provides the external world with a way to adjust the bleat level for gizmos. 80 | */ 81 | func Set_bleat_level( v uint ) { 82 | obj_sheep.Set_level( v ) 83 | } 84 | -------------------------------------------------------------------------------- /gizmos/lite.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: lite 24 | Abstract: Functions specifically added to support qos-lite. 25 | These should later be broken into better organised files, but since 26 | this is a deathmarch they are all stuck in here to make it easy (but 27 | messy). 28 | Date: 28 April 2014 29 | Author: E. Scott Daniels 30 | 29 Jul 2014 : Mlag support 31 | 32 | */ 33 | 34 | package gizmos 35 | 36 | import ( 37 | //"bufio" 38 | "encoding/json" 39 | //"fmt" 40 | "os" 41 | //"strings" 42 | //"time" 43 | ) 44 | 45 | 46 | /* 47 | Reads the file which is assumed to contain nothing but the json link 48 | in floodlight syntax. 49 | */ 50 | func Read_json_links( fname string ) ( links []FL_link_json, err error ) { 51 | 52 | f, err := os.Open( fname ) 53 | links = nil 54 | 55 | if err != nil { 56 | return; 57 | } 58 | defer f.Close() 59 | 60 | 61 | links = make( []FL_link_json, 0 ) 62 | jdecoder := json.NewDecoder( f ) 63 | err = jdecoder.Decode( &links ) 64 | 65 | //TODO: parse the list of links and create 'internal' linkes e.g. br-em1...br-int and br-em2...br-int 66 | // for now we strip @interface name from the switch id 67 | /* 68 | for i := range links { 69 | n := strings.Index( links[i].Dst_switch, "@" ) 70 | if n >= 0 { // if this is indicates the interface name 71 | links[i].Dst_switch = links[i].Dst_switch[0:n] // ditch it for now 72 | } 73 | } 74 | */ 75 | 76 | return 77 | } 78 | 79 | 80 | /* 81 | Request vm information from openstack and generate the 'host json' that is a 82 | match for the floodlight dev api output: 83 | dev[0]: 84 | entityClass = DefaultEntityClass 85 | mac[0] = fa:de:ad:a9:9d:c5 86 | ipv4[0] = 10.67.0.4 87 | attachmentPoint[0]: 88 | switchDPID = 00:00:d2:56:96:3f:7d:46 89 | port = 113.00 90 | errorStatus = null/undefined 91 | lastSeen = 1398705932064.00 92 | 93 | 94 | This must be a part of network manger because the net struct is where all the maps are and it's 95 | just easier to keep it there. 96 | */ 97 | 98 | -------------------------------------------------------------------------------- /gizmos/mbox.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: mbox 24 | Abstract: "object" that represents a middle box for a steering reservation. 25 | Date: 24 June 2014 26 | Author: E. Scott Daniels 27 | 28 | Mods: 29 | */ 30 | 31 | package gizmos 32 | 33 | import ( 34 | //"bufio" 35 | //"encoding/json" 36 | //"flag" 37 | "fmt" 38 | //"io/ioutil" 39 | //"html" 40 | //"net/http" 41 | //"os" 42 | //"strings" 43 | //"time" 44 | 45 | //"github.com/att/gopkgs/clike" 46 | ) 47 | 48 | type Mbox struct { 49 | id *string // name or id of the VM 50 | mac *string // mac address for routing to the box 51 | swid *string // switch that owns the connection to the mobx (could be phost for OVS and late binding actions) 52 | swport int // port that the box is attached to (may be -128 for late binding) 53 | } 54 | 55 | /* 56 | Constructor; creates a middle box 57 | */ 58 | func Mk_mbox( id *string, mac *string, swid *string, swport int ) ( mb *Mbox ) { 59 | 60 | mb = nil 61 | 62 | mb = &Mbox { 63 | id: id, 64 | mac: mac, 65 | swid: swid, 66 | swport: swport, 67 | } 68 | 69 | return 70 | } 71 | 72 | /* 73 | Returns the id/name -- which ever was given when created. 74 | */ 75 | func (mb *Mbox) Get_id( ) ( *string ) { 76 | return mb.id 77 | } 78 | 79 | /* 80 | Returns the switch ID and port. 81 | */ 82 | func (mb *Mbox) Get_sw_port( ) ( *string, int ) { 83 | return mb.swid, mb.swport 84 | } 85 | 86 | /* 87 | Returns the mac 88 | */ 89 | func (mb *Mbox) Get_mac( ) ( *string ) { 90 | return mb.mac 91 | } 92 | 93 | /* 94 | Returns all information. 95 | */ 96 | func (mb *Mbox) Get_values( ) ( id *string, mac *string, swid *string, swport int ) { 97 | return mb.id, mb.mac, mb.swid, mb.swport 98 | } 99 | 100 | /* 101 | Generate a json representation. 102 | */ 103 | func (mb *Mbox) To_json( ) ( *string ) { 104 | s := fmt.Sprintf( `{ "id": %q, "mac": %q, "swid": %q, "swport": %d }`, *mb.id, *mb.mac, *mb.swid, mb.swport ) 105 | return &s 106 | } 107 | -------------------------------------------------------------------------------- /gizmos/mlag.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: mlag 24 | Abstract: Manages a list of links that belong to the same mlag group. The mlags track 25 | links using a link's obligation so that if multiple links share the same 26 | obligation (bidirectional), then we avoid having to worry about referencing 27 | the same obligation twice. 28 | 29 | Date: 28 Jul 2014 30 | Author: E. Scott Daniels 31 | 32 | Mods: 33 | 34 | */ 35 | 36 | package gizmos 37 | 38 | import ( 39 | //"bufio" 40 | //"fmt" 41 | //"os" 42 | //"strings" 43 | //"time" 44 | ) 45 | 46 | // -------------------------------------------------------------------------------------- 47 | 48 | /* 49 | Defines an mlag which is a name and a list of link pointers. 50 | */ 51 | type Mlag struct { 52 | name *string 53 | llist []*Obligation // list of links (tracked by obligation so as not to dup links that share the obligation) 54 | lidx int // last non-nil value in the list 55 | } 56 | 57 | /* 58 | Create an mlag struct and return a pointer to it. Nil pointer 59 | indicates error. 60 | */ 61 | func Mk_mlag( name *string, lob *Obligation ) ( m *Mlag ) { 62 | m = nil 63 | if name == nil { // not permitted 64 | return 65 | } 66 | 67 | m = &Mlag { 68 | name: name, 69 | } 70 | 71 | m.llist = make( []*Obligation, 10 ) 72 | if lob != nil { 73 | m.llist[0] = lob 74 | m.lidx = 1 75 | } 76 | 77 | return 78 | } 79 | 80 | /* 81 | Add a link to the mlag set. 82 | */ 83 | func (m *Mlag) Add_link( lob *Obligation ) { 84 | 85 | if m == nil || lob == nil { 86 | return 87 | } 88 | 89 | nil_entry := m.lidx // insert into a hole if found 90 | for i := 0; i < m.lidx; i++ { // we prevent dups with a search; may want to hash on link name in future 91 | if m.llist[i] == nil { 92 | nil_entry = i 93 | } else { 94 | if m.llist[i] == lob { // already referenced 95 | return 96 | } 97 | } 98 | } 99 | 100 | if nil_entry >= len( m.llist ) { 101 | new_list := make( []*Obligation, m.lidx + 10 ) 102 | for i := range m.llist { 103 | new_list[i] = m.llist[i] // copy into new 104 | } 105 | 106 | m.llist = new_list 107 | } 108 | 109 | m.llist[nil_entry] = lob 110 | if nil_entry >= m.lidx { // bump only if we added to end rather than replaced nil entry 111 | m.lidx++ 112 | } 113 | } 114 | 115 | 116 | /* 117 | Remove a link from the mlag group. 118 | */ 119 | func (m *Mlag) Rm_link( lob *Obligation ) { 120 | for i := 0; i < m.lidx; i++ { 121 | if m.llist[i] == lob { 122 | m.llist[i] = nil 123 | if i == m.lidx - 1 { // dec end marker if last in list deleted 124 | m.lidx-- 125 | } 126 | return 127 | } 128 | } 129 | } 130 | 131 | /* 132 | Run each link in the list and increase the utilisation of the link. We will _not_ inc the utilisation 133 | of the obligation that is passed in assuming it was bumpped initially which triggered the inc across 134 | the mlag. 135 | */ 136 | func (m *Mlag) Inc_utilisation( commence int64, conclude int64, delta int64, usr *Fence, skip *Obligation ) { 137 | for i := 0; i < m.lidx; i++ { 138 | if m.llist[i] != nil && m.llist[i] != skip { 139 | msg := m.llist[i].Inc_utilisation( commence, conclude, delta, usr ) 140 | if msg != nil { 141 | obj_sheep.Baa( 1, "utilisation increased for mlag %s: %s", m.name, *msg ) 142 | } 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /gizmos/pledge.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: pledge interface 24 | Abstract: Defines what constitutes a pledge interface. 25 | Implemented by pledge_bw, pledge_mirror, pledge_steer and 26 | maybe others. 27 | 28 | Functions defined by the interface should make sense for ALL 29 | pledge types. If they don't then the type(s) that require 30 | them should implement them and the user will need to convert 31 | the more generic interface type to the specific type to invoke 32 | the function needed. Examples of this which have been 33 | specifically omitted: Get_values(), Clone(), Set_path_list. 34 | 35 | There are also some generic functions such as json2pledge(). 36 | Date: 21 May 2015 37 | Author: E. Scott Daniels 38 | 39 | Mods: 16 Aug 2015 - listed funcs provided by Pledge_base, and those that must be written per Pledge type 40 | 12 Apr 2016 - Support for duplicate refresh capability. 41 | */ 42 | 43 | package gizmos 44 | 45 | import ( 46 | "fmt" 47 | "encoding/json" 48 | ) 49 | 50 | /* 51 | This is the interface that all Pledge types must implement. 52 | Most of these functions have a default implementation in Pledge_base. 53 | */ 54 | type Pledge interface { 55 | // The following are implemented by Pledge_base 56 | Concluded_recently( window int64 ) ( bool ) 57 | Commenced_recently( window int64 ) ( bool ) 58 | Get_id( ) ( *string ) 59 | Get_window( ) ( int64, int64 ) 60 | Is_active( ) ( bool ) 61 | Is_active_soon( window int64 ) ( bool ) 62 | Is_expired( ) ( bool ) 63 | Is_extinct( window int64 ) ( bool ) 64 | Is_pending( ) ( bool ) 65 | Is_pushed( ) (bool) 66 | Is_paused( ) ( bool ) 67 | Is_valid_cookie( c *string ) ( bool ) 68 | Pause( bool ) 69 | Reset_pushed( ) 70 | Resume( bool ) 71 | Same_anchors( *string, *string ) ( bool ) 72 | Set_expiry( expiry int64 ) 73 | Set_pushed() 74 | 75 | // The following must be implemented by each separate Pledge type 76 | Equals( *Pledge ) ( bool ) 77 | Get_hosts() ( *string, *string ) 78 | Has_host( *string ) ( bool ) 79 | Nuke() 80 | String() ( string ) 81 | To_chkpt( ) ( string ) 82 | To_json( ) ( string ) 83 | To_str() ( string ) 84 | 85 | //Set_matchv6( bool ) 86 | //Get_ptype( ) ( int ) users should use assertion or type determination in switch for these 87 | //Is_ptype( kind int ) ( bool ) // kind is one of the PT constants 88 | } 89 | 90 | // generic struct to unpack any type of pledge in order to determine the type 91 | // This must only contain fields that exist in all pledge types, and only 92 | // the fields that are needed to determine the type. 93 | type J2p struct { 94 | Ptype *int 95 | } 96 | 97 | /* 98 | Given a string that contains valid json, unpack it and examine 99 | the ptype. Based on ptype, allocate a specific pledge block and 100 | invoke it's function to unpack the string. 101 | */ 102 | func Json2pledge( jstr *string ) ( p *Pledge, err error ) { 103 | var pi Pledge 104 | 105 | jp := new( J2p ) 106 | err = json.Unmarshal( []byte( *jstr ), &jp ) 107 | if err == nil { 108 | if jp.Ptype != nil { 109 | switch *jp.Ptype { 110 | case PT_BANDWIDTH: 111 | bp := new( Pledge_bw ) 112 | bp.From_json( jstr ) 113 | pi = Pledge( bp ) // convert to interface type 114 | 115 | case PT_OWBANDWIDTH: // one way bandwidth 116 | obp := new( Pledge_bwow ) 117 | obp.From_json( jstr) 118 | pi = Pledge( obp ) 119 | 120 | case PT_MIRRORING: 121 | mp := new( Pledge_mirror ) 122 | mp.From_json( jstr ) 123 | pi = Pledge( mp ) // convert to interface type 124 | 125 | case PT_STEERING: 126 | mp := new( Pledge_steer ) 127 | mp.From_json( jstr ) 128 | pi = Pledge( mp ) // convert to interface type 129 | 130 | case PT_PASSTHRU: 131 | pt := new( Pledge_pass ) 132 | pt.From_json( jstr ) 133 | pi = Pledge( pt ) // convert to interface type 134 | 135 | default: 136 | err = fmt.Errorf( "unknown pledge type in json: %d: %s", *jp.Ptype, *jstr ) 137 | return 138 | } 139 | } else { 140 | err = fmt.Errorf( "no ptype found in json, unable to convert to pledge: %s", *jstr ) 141 | } 142 | } 143 | 144 | p = &pi 145 | return 146 | } 147 | -------------------------------------------------------------------------------- /gizmos/pledge_base.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: pledge base struct 24 | Abstract: This defines the basic data members and functions that are included in 25 | all pledge structs. It implements most, but not all of, the Pledge interface. 26 | 27 | Pledge types should include an anonymous, unnamed Pledge_base as the first 28 | element of their defining type, in order to pull in these fields and functions. 29 | 30 | Note: pledge_window could probably be combined with this file now, but as 31 | the main point of this exercise was to remove duplicated functions, I will 32 | leave that separate for now. 33 | 34 | Date: 16 Aug 2015 35 | Author: E. Scott Daniels / Robert Eby 36 | 37 | Mods: 12 Apr 2016 - Duplicate refresh support. 38 | */ 39 | 40 | package gizmos 41 | 42 | type Pledge_base struct { 43 | id *string // name that the client can use to manage (modify/delete) 44 | window *pledge_window // the window of time for which the pledge is active 45 | pushed bool // set when pledge has been pushed into openflow or openvswitch 46 | paused bool // set if reservation has been paused 47 | usrkey *string // a 'cookie' supplied by the user to prevent any other user from modifying 48 | } 49 | 50 | /* 51 | Returns true if pledge concluded between (now - window) and now-1. 52 | */ 53 | func (p *Pledge_base) Concluded_recently( window int64 ) ( bool ) { 54 | if p == nil { 55 | return false 56 | } 57 | return p.window.concluded_recently( window ) 58 | } 59 | 60 | /* 61 | Returns true if pledge started recently (between now and now - window seconds) and 62 | has not expired yet. If the pledge started within the window, but expired before 63 | the call to this function false is returned. 64 | */ 65 | func (p *Pledge_base) Commenced_recently( window int64 ) ( bool ) { 66 | if p == nil { 67 | return false 68 | } 69 | return p.window.commenced_recently( window ) 70 | } 71 | 72 | /* 73 | Returns a pointer to the ID string of the pledge. 74 | */ 75 | func (p *Pledge_base) Get_id( ) ( *string ) { 76 | if p == nil { 77 | return nil 78 | } 79 | return p.id 80 | } 81 | 82 | /* 83 | Return the commence and expiry times. 84 | */ 85 | func (p *Pledge_base) Get_window( ) ( int64, int64 ) { 86 | if p == nil { 87 | return 0, 0 88 | } 89 | return p.window.get_values() 90 | } 91 | 92 | /* 93 | Returns true if the pledge is currently active (the commence time is <= than the current time 94 | and the expiry time is > the current time. 95 | */ 96 | func (p *Pledge_base) Is_active( ) ( bool ) { 97 | if p == nil { 98 | return false 99 | } 100 | return p.window.is_active() 101 | } 102 | 103 | /* 104 | Returns true if pledge is active now, or will be active before elapsed seconds have passed. 105 | */ 106 | func (p *Pledge_base) Is_active_soon( window int64 ) ( bool ) { 107 | if p == nil { 108 | return false 109 | } 110 | return p.window.is_active_soon( window ) 111 | } 112 | 113 | /* 114 | Returns true if the pledge has expired (the current time is greater than 115 | the expiry time in the pledge). 116 | */ 117 | func (p *Pledge_base) Is_expired( ) ( bool ) { 118 | if p == nil { 119 | return true 120 | } 121 | return p.window.is_expired() 122 | } 123 | 124 | /* 125 | Returns true if pledge expired long enough ago that it can safely be discarded. 126 | The window is the number of seconds that the pledge must have been expired to 127 | be considered extinct. 128 | */ 129 | func (p *Pledge_base) Is_extinct( window int64 ) ( bool ) { 130 | if p == nil { 131 | return false 132 | } 133 | return p.window.is_extinct( window ) 134 | } 135 | 136 | /* 137 | Returns true if the pledge has not become active (the commence time is >= the current time). 138 | */ 139 | func (p *Pledge_base) Is_pending( ) ( bool ) { 140 | if p == nil { 141 | return false 142 | } 143 | return p.window.is_pending() 144 | } 145 | 146 | /* 147 | Returns true if the pushed flag has been set to true. 148 | */ 149 | func (p *Pledge_base) Is_pushed( ) (bool) { 150 | if p == nil { 151 | return false 152 | } 153 | return p.pushed 154 | } 155 | 156 | /* 157 | Returns true if the reservation is paused. 158 | */ 159 | func (p *Pledge_base) Is_paused( ) ( bool ) { 160 | if p == nil { 161 | return false 162 | } 163 | return p.paused 164 | } 165 | 166 | /* 167 | Check the cookie passed in and return true if it matches the cookie on the 168 | pledge. 169 | */ 170 | func (p *Pledge_base) Is_valid_cookie( c *string ) ( bool ) { 171 | if p == nil || c == nil { 172 | return false 173 | } 174 | return *c == *p.usrkey 175 | } 176 | 177 | // There is NOT a toggle pause on purpose; don't add one :) 178 | 179 | /* 180 | Puts the pledge into paused state and optionally resets the pushed flag. 181 | */ 182 | func (p *Pledge_base) Pause( reset bool ) { 183 | if p != nil { 184 | p.paused = true 185 | if reset { 186 | p.pushed = false; 187 | } 188 | } 189 | } 190 | 191 | /* 192 | Puts the pledge into an unpaused (normal) state and optionally resets the pushed flag. 193 | */ 194 | func (p *Pledge_base) Resume( reset bool ) { 195 | if p != nil { 196 | p.paused = false 197 | if reset { 198 | p.pushed = false; 199 | } 200 | } 201 | } 202 | 203 | /* 204 | Sets a new expiry value on the pledge. 205 | */ 206 | func (p *Pledge_base) Set_expiry ( v int64 ) { 207 | if p != nil { 208 | p.window.set_expiry_to( v ) 209 | p.pushed = false // force it to be resent to adjust times 210 | } 211 | } 212 | 213 | /* 214 | Sets the pushed flag to true. 215 | */ 216 | func (p *Pledge_base) Set_pushed( ) { 217 | if p != nil { 218 | p.pushed = true 219 | } 220 | } 221 | 222 | /* 223 | Resets the pushed flag to false. 224 | */ 225 | func (p *Pledge_base) Reset_pushed( ) { 226 | if p != nil { 227 | p.pushed = false 228 | } 229 | } 230 | 231 | /* 232 | 233 | */ 234 | func (p *Pledge_base) Same_anchors( a1 *string, a2 *string ) (bool ) { 235 | return false; 236 | } 237 | -------------------------------------------------------------------------------- /gizmos/pledge_test.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: pledge_test 24 | Abstract: test functions that test various components of pledge and pledge window. 25 | Date: 01 June 2015 26 | Author: E. Scott Daniels 27 | 28 | */ 29 | 30 | package gizmos 31 | 32 | import ( 33 | "fmt" 34 | "os" 35 | "testing" 36 | "time" 37 | 38 | ) 39 | 40 | /* 41 | make a window and show error if it does 42 | */ 43 | func new_pw( c int64, e int64 ) ( *pledge_window ) { 44 | 45 | p, err := mk_pledge_window( c, e ) 46 | if err != nil { 47 | fmt.Fprintf( os.Stderr, "ERROR: did not create pledge window: %s\n", err ) 48 | } 49 | 50 | return p 51 | } 52 | 53 | 54 | func Test_pwo( t *testing.T ) { 55 | failures :=0 56 | now := time.Now().Unix() 57 | p1_start := now + 3600 // ensure all start times are in future so window creates 58 | p1_end := now + 7200 59 | p1 := new_pw( p1_start, p1_end ) // master window to compare others with 60 | 61 | p2 := new_pw( p1_start - 600, p1_start - 300 ) // completely before p1 (expect false) 62 | p3 := new_pw( p1_end + 800, p1_end + 900 ) // completely after p1 (expect false) 63 | p4 := new_pw( p1_start + 300, p1_end + 800 ) // commence overlap (expect true) 64 | p5 := new_pw( p1_start - 800, p1_start + 300 ) // expiry overlap (expect true) 65 | p6 := new_pw( p1_start - 300, p1_end + 800 ) // completely engulf (expect true) 66 | p7 := new_pw( p1_start -300 , p1_start ) // ending exactly where p1 starts (expect false) 67 | 68 | fmt.Fprintf( os.Stderr, "\n------- pledge window overlap tests ---------\n" ); 69 | if p1.overlaps( p2 ) { 70 | fmt.Fprintf( os.Stderr, "FAIL: pwindow1 reports overlap with pwindow 2\n" ) 71 | failures++ 72 | } 73 | 74 | if p1.overlaps( p3 ) { 75 | fmt.Fprintf( os.Stderr, "FAIL: pwindow1 reports overlap with pwindow 3\n" ) 76 | failures++ 77 | } 78 | 79 | // p4-6 do overlap and so failure if it returns false 80 | if !p1.overlaps( p4 ) { 81 | fmt.Fprintf( os.Stderr, "FAIL: pwindow1 does not report overlap with pwindow 4\n" ) 82 | failures++ 83 | } 84 | 85 | if !p1.overlaps( p5 ) { 86 | fmt.Fprintf( os.Stderr, "FAIL: pwindow1 does not report overlap with pwindow 5\n" ) 87 | failures++ 88 | } 89 | 90 | if !p1.overlaps( p6 ) { 91 | fmt.Fprintf( os.Stderr, "FAIL: pwindow1 does not report overlap with pwindow 6\n" ) 92 | failures++ 93 | } 94 | 95 | // end time is same as p1 start time expect false 96 | if p1.overlaps( p7 ) { 97 | fmt.Fprintf( os.Stderr, "FAIL: pwindow1 reports overlap with pwindow 7\n" ) 98 | failures++ 99 | } 100 | 101 | if failures == 0 { 102 | fmt.Fprintf( os.Stderr, "OK: all pledge window overlap tests pass\n" ) 103 | } else { 104 | t.Fail() 105 | } 106 | 107 | fmt.Fprintf( os.Stderr, "\n" ) 108 | } 109 | 110 | /* 111 | Test to see that pledge window fails to create if time is too far in future 112 | */ 113 | func Test_pw_excessive( t *testing.T ) { 114 | fmt.Fprintf( os.Stderr, "\n------- pledge window tests ---------\n" ); 115 | 116 | p1_start := time.Now().Unix() + 3600 // ensure all start times are in future so window creates 117 | p, err := mk_pledge_window( p1_start, p1_start + (20 * 86400 * 365) ) // too far in the future (expect false) 118 | if p == nil { 119 | fmt.Fprintf( os.Stderr, "OK: window with excessive end time was not allocated as expected\n" ) 120 | } else { 121 | fmt.Fprintf( os.Stderr, "FAIL: window with excessive end time did not fail: %s\n", err ) 122 | t.Fail() 123 | } 124 | } 125 | 126 | /* 127 | */ 128 | func Test_ob_validtime( t *testing.T ) { 129 | fmt.Fprintf( os.Stderr, "\n------- valid obligattion tests ---------\n" ); 130 | 131 | if Valid_obtime( 1735707600-1 ) { // expect pass, time just under bounds 132 | fmt.Fprintf( os.Stderr, "OK: max-1 time returned valid\n" ) 133 | } else { 134 | fmt.Fprintf( os.Stderr, "FAIL: max-1 time didn't return valid\n" ) 135 | t.Fail() 136 | } 137 | 138 | if Valid_obtime( time.Now().Unix() + 1 ) { //expect pass, time just under bounds 139 | fmt.Fprintf( os.Stderr, "OK: now+1 time returned valid\n" ) 140 | } else { 141 | fmt.Fprintf( os.Stderr, "FAIL: now+1 time didn't return valid\n" ) 142 | t.Fail() 143 | } 144 | 145 | if Valid_obtime( 1735707600+1 ) { // expect failure, time out of bounds 146 | fmt.Fprintf( os.Stderr, "FAIL: max+1 time returned valid\n" ) 147 | t.Fail() 148 | } else { 149 | fmt.Fprintf( os.Stderr, "OK: max+1 time returned invalid\n" ) 150 | } 151 | 152 | if Valid_obtime( time.Now().Unix() - 1 ) { // expect failure, time out of bounds 153 | fmt.Fprintf( os.Stderr, "FAIL: now-1 time returned valid\n" ) 154 | t.Fail() 155 | } else { 156 | fmt.Fprintf( os.Stderr, "OK: now-1 time returned invalid\n" ) 157 | } 158 | } 159 | 160 | func Test_bw_equals( t *testing.T ) { 161 | h1 := "host1" 162 | h2 := "host2" 163 | h3 := "host3" 164 | p1 := "4360" 165 | p2 := "" 166 | v1 := "1" 167 | v2 := "2" 168 | v3 := "3" 169 | key := "cookie" 170 | id1 := "r1" 171 | 172 | 173 | failures := 0 174 | now := time.Now().Unix() 175 | 176 | fmt.Fprintf( os.Stderr, "\n----------- pledge equality tests --------------\n" ) 177 | bp1, _ := Mk_bw_pledge( &h1, &h2, &p1, &p2, now+300, now+600, 10000, 10000, &id1, &key, 42, false ) 178 | bp1.Set_vlan( &v1, &v2 ) 179 | 180 | bp2, _ := Mk_bw_pledge( &h1, &h2, &p1, &p2, now+400, now+800, 10000, 10000, &id1, &key, 42, false ) // different times, but overlap (expect equal) 181 | bp2.Set_vlan( &v1, &v2 ) 182 | 183 | bp3, _ := Mk_bw_pledge( &h1, &h2, &p1, &p2, now+800, now+1800, 10000, 10000, &id1, &key, 42, false ) // time window after p1 (expect not equal) 184 | bp3.Set_vlan( &v1, &v2 ) 185 | 186 | bp4, _ := Mk_bw_pledge( &h3, &h2, &p1, &p2, now+300, now+600, 10000, 10000, &id1, &key, 42, false ) // different name (expect not equal) 187 | bp4.Set_vlan( &v1, &v2 ) 188 | 189 | bp5, _ := Mk_bw_pledge( &h2, &h1, &p2, &p1, now+300, now+600, 10000, 10000, &id1, &key, 42, false ) // names, proto reversed (expect equal) 190 | bp5.Set_vlan( &v2, &v1 ) 191 | 192 | bp6, _ := Mk_bw_pledge( &h2, &h1, &p2, &p1, now+300, now+600, 10000, 10000, &id1, &key, 42, false ) // names, proto reversed different vlans (expect not equal) 193 | bp6.Set_vlan( &v3, &v1 ) 194 | 195 | 196 | gp2 := Pledge(bp2) // convert to generic pledge for calls 197 | gp3 := Pledge(bp3) 198 | gp4 := Pledge(bp4) 199 | gp5 := Pledge(bp5) 200 | gp6 := Pledge(bp6) 201 | if !bp1.Equals( &gp2 ) { 202 | failures++ 203 | fmt.Fprintf( os.Stderr, "FAIL: bp1 reporeted not equal to bp2 (overlapping time)\n" ) 204 | } 205 | 206 | if bp1.Equals( &gp3 ) { 207 | failures++ 208 | fmt.Fprintf( os.Stderr, "FAIL: bp1 reporeted equal to bp3 (non overlap time)\n" ) 209 | } 210 | 211 | if bp1.Equals( &gp4 ) { 212 | failures++ 213 | fmt.Fprintf( os.Stderr, "FAIL: bp1 reporeted equal to bp4 (different name)\n" ) 214 | } 215 | 216 | if !bp1.Equals( &gp5 ) { 217 | failures++ 218 | fmt.Fprintf( os.Stderr, "FAIL: bp1 reporeted not equal to bp5 (names reversed)\n" ) 219 | } 220 | 221 | if bp1.Equals( &gp6 ) { 222 | failures++ 223 | fmt.Fprintf( os.Stderr, "FAIL: bp1 reporeted equal to bp6 (names reversed, vlan different)\n" ) 224 | } 225 | 226 | if failures > 0 { 227 | t.Fail() 228 | } else { 229 | fmt.Fprintf( os.Stderr, "OK: all bandwidth pledge equal tests passed\n" ) 230 | } 231 | fmt.Fprintf( os.Stderr, "\n" ) 232 | } 233 | -------------------------------------------------------------------------------- /gizmos/pledge_window.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: pledge_window 24 | Abstract: Struct that manages a window of time for any pledge type and the 25 | functions which make testing times against the window easier. 26 | Pledge times are managed at the second level; no need for more 27 | precision for this. This structure is local to gizmos so nothing 28 | should be visible to the outside world. 29 | 30 | Date: 20 May 2015 31 | Author: E. Scott Daniels 32 | 33 | Mods: 28 Jul 2015 : Added upper bounds check for expiry time. 34 | */ 35 | 36 | package gizmos 37 | 38 | import ( 39 | "fmt" 40 | "time" 41 | ) 42 | 43 | type pledge_window struct { 44 | commence int64 45 | expiry int64 46 | } 47 | 48 | /* 49 | Make a new pledge_window. If the commence time is earlier than now, it is adjusted 50 | to be now. If the expry time is before the adjusted commence time, then a nil 51 | pointer and error are returned. 52 | */ 53 | func mk_pledge_window( commence int64, expiry int64 ) ( pw *pledge_window, err error ) { 54 | now := time.Now().Unix() 55 | err = nil 56 | pw = nil 57 | 58 | if commence < now { 59 | commence = now 60 | } 61 | 62 | if expiry < commence { 63 | err = fmt.Errorf( "bad expiry submitted, already expired: now=%d expiry=%d", now, expiry ); 64 | obj_sheep.Baa( 2, "pledge: %s", err ) 65 | return 66 | } 67 | 68 | if ! Valid_obtime( expiry ) { // if expiry is less than max obligation time 69 | err = fmt.Errorf( "bad expiry submitted, too far in the future: expiry=%d", expiry ); 70 | obj_sheep.Baa( 2, "pledge: %s", err ) 71 | return 72 | } 73 | 74 | pw = &pledge_window { 75 | commence: commence, 76 | expiry: expiry, 77 | } 78 | 79 | return 80 | } 81 | 82 | /* 83 | Adjust window. Returns a valid commence time (if earlier than now) or 0 if the 84 | time window is not valid. 85 | func adjust_window( commence int64, conclude int64 ) ( adj_start int64, err error ) { 86 | 87 | now := time.Now().Unix() 88 | err = nil 89 | 90 | if commence < now { // ajust forward to better play with windows on the paths 91 | adj_start = now 92 | } else { 93 | adj_start = commence 94 | } 95 | 96 | if conclude <= adj_start { // bug #156 fix 97 | err = fmt.Errorf( "bad expiry submitted, already expired: now=%d expiry=%d", now, conclude ); 98 | obj_sheep.Baa( 2, "pledge: %s", err ) 99 | return 100 | } 101 | 102 | return 103 | } 104 | */ 105 | 106 | func (p *pledge_window) clone( ) ( npw *pledge_window ) { 107 | if p == nil { 108 | return nil 109 | } 110 | 111 | npw = &pledge_window { 112 | expiry: p.expiry, 113 | commence: p.commence, 114 | } 115 | 116 | return 117 | } 118 | 119 | /* 120 | Return the state as a string and the amount of time in the 121 | past (seconds) that the pledge expired, or the amount of 122 | time in the future that the pledge will be active. Caption 123 | is a string such as "ago" that can be used following the value 124 | if needed. 125 | */ 126 | func (p *pledge_window) state_str( ) ( state string, caption string, diff int64 ) { 127 | if p == nil { 128 | return "EXPIRED", "no window", 0 129 | } 130 | 131 | now := time.Now().Unix() 132 | 133 | if now >= p.expiry { 134 | state = "EXPIRED" 135 | caption = "ago" 136 | } else { 137 | if now < p.commence { 138 | state = "PENDING" 139 | diff = p.commence - now 140 | caption = "from now" 141 | } else { 142 | state = "ACTIVE" 143 | diff = p.expiry - now 144 | caption = "remaining" 145 | } 146 | } 147 | 148 | return state, caption, diff 149 | } 150 | 151 | /* 152 | Extend the expiry time by n seconds. N may be negative and will not set the 153 | expiry time earlier than now. 154 | */ 155 | func (p *pledge_window) extend_by( n int64 ) { 156 | if p == nil { 157 | return 158 | } 159 | 160 | p.expiry += n; 161 | 162 | if n < 0 { 163 | now := time.Now().Unix() 164 | if p.expiry < now { 165 | p.expiry = now 166 | } 167 | } 168 | } 169 | 170 | /* 171 | Set the expiry time to the timestamp passed in. 172 | It is valid to set the expiry time to a time before the current time. 173 | */ 174 | func (p *pledge_window) set_expiry_to( new_time int64 ) { 175 | p.expiry = new_time; 176 | } 177 | 178 | /* 179 | Returns true if the pledge has expired (the current time is greather than 180 | the expiry time in the pledge). 181 | */ 182 | func (p *pledge_window) is_expired( ) ( bool ) { 183 | if p == nil { 184 | return true 185 | } 186 | 187 | return time.Now().Unix( ) >= p.expiry 188 | } 189 | 190 | /* 191 | Returns true if the pledge has not become active (the commence time is >= the current time). 192 | */ 193 | func (p *pledge_window) is_pending( ) ( bool ) { 194 | if p == nil { 195 | return false 196 | } 197 | return time.Now().Unix( ) < p.commence 198 | } 199 | 200 | /* 201 | Returns true if the pledge is currently active (the commence time is <= than the current time 202 | and the expiry time is > the current time. 203 | */ 204 | func (p *pledge_window) is_active( ) ( bool ) { 205 | if p == nil { 206 | return false 207 | } 208 | 209 | now := time.Now().Unix() 210 | return p.commence < now && p.expiry > now 211 | } 212 | 213 | /* 214 | Returns true if pledge is active now, or will be active before elapsed seconds (window) have passed. 215 | */ 216 | func (p *pledge_window) is_active_soon( window int64 ) ( bool ) { 217 | if p == nil { 218 | return false 219 | } 220 | 221 | now := time.Now().Unix() 222 | return (p.commence >= now) && p.commence <= (now + window) 223 | } 224 | 225 | func (p *pledge_window) get_values( ) ( commence int64, expiry int64 ) { 226 | if p == nil { 227 | return 0, 0 228 | } 229 | 230 | return p.commence, p.expiry 231 | } 232 | 233 | /* 234 | Returns true if pledge concluded between (now - window) and now-1. 235 | If pledge_window is nil, then we return true. 236 | */ 237 | func (p *pledge_window) concluded_recently( window int64 ) ( bool ) { 238 | if p == nil { 239 | return true 240 | } 241 | 242 | now := time.Now().Unix() 243 | return (p.expiry < now) && (p.expiry >= now - window) 244 | } 245 | 246 | /* 247 | Returns true if pledge started recently (between now and now - window seconds) and 248 | has not expired yet. If the pledge started within the window, but expired before 249 | the call to this function false is returned. 250 | */ 251 | func (p *pledge_window) commenced_recently( window int64 ) ( bool ) { 252 | if p == nil { 253 | return false 254 | } 255 | 256 | now := time.Now().Unix() 257 | return (p.commence >= (now - window)) && (p.commence <= now ) && (p.expiry > now) 258 | } 259 | 260 | /* 261 | Returns true if pledge expired long enough ago, based on the window timestamp 262 | passed in, that it can safely be discarded. The window is the number of 263 | seconds that the pledge must have been expired to be considered extinct. 264 | */ 265 | func (p *pledge_window) is_extinct( window int64 ) ( bool ) { 266 | if p == nil { 267 | return false 268 | } 269 | 270 | now := time.Now().Unix() 271 | return p.expiry <= now - window 272 | } 273 | 274 | /* 275 | Test this window (p) against a second window (p2) to see if they overlap. 276 | Windows where commence is equal to expiry, or expiry is equal to commence 277 | (6, and 8 below) are not considered overlapping. 278 | 279 | pc|---------------------------------|pe 280 | . . 281 | T p2c|----.------|p2e . (1) 282 | T .p2c|-----------|p2e . (2) 283 | T . p2c|-----.-----|p2e (3) 284 | T p2c|----.---------------------------------.----|p2e (4) 285 | T p2c|---------------------------------|p2e (5) 286 | F . p2c|--------|p2e (6) 287 | F p2c|--| . . (7) 288 | F p2c|-----| . (8) 289 | F . . p2c|--|p2e (9) 290 | */ 291 | func (p *pledge_window) overlaps( p2 *pledge_window ) ( bool ) { 292 | if p == nil || p2 == nil { 293 | return false 294 | } 295 | 296 | if p2.commence >= p.commence && p2.commence < p.expiry { //(2,3) 297 | return true; 298 | } 299 | 300 | if p2.expiry > p.commence && p2.expiry <= p.expiry { //(1,2) 301 | return true; 302 | } 303 | 304 | if p2.commence <= p.commence && p2.expiry >= p.expiry { //(4,5) 305 | return true; 306 | } 307 | 308 | return false 309 | } 310 | -------------------------------------------------------------------------------- /gizmos/queue.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: queue 24 | Abstract: Represents a queue, mapping it to a source host and 25 | a specific bandwidth maximum. 26 | 27 | Date: 06 February 2014 28 | Author: E. Scott Daniels 29 | 30 | Mods: 07 Jul 2014 - Added To_str_pos() function to generate strings 31 | only if the bandwidth for the queue is greater than zero. 32 | 18 Jun 2015 - Ensure bandwidth amount doesn't go negative. 33 | */ 34 | 35 | package gizmos 36 | 37 | import ( 38 | //"bufio" 39 | //"encoding/json" 40 | //"flag" 41 | "fmt" 42 | //"io/ioutil" 43 | //"html" 44 | //"net/http" 45 | //"os" 46 | //"strings" 47 | //"time" 48 | 49 | //"github.com/att/gopkgs/clike" 50 | ) 51 | 52 | type Queue struct { 53 | Id *string // the id of the queue; likely a host/VM name, mac, or ip or vm1-vm2 pair 54 | bandwidth int64 // bandwidth associated with the queue 55 | pri int // priority given to ovs when setting queues 56 | qnum int // the queue number (we cannot depend on ordering) 57 | exref *string // switch/port (other info?) that queue setting function will need 58 | } 59 | 60 | /* 61 | constructor 62 | */ 63 | func Mk_queue( bw int64, id *string, num int, priority int, ref_data *string ) ( q *Queue ) { 64 | q = &Queue { 65 | bandwidth: bw, 66 | Id: id, 67 | qnum: num, 68 | pri: priority, 69 | exref: ref_data, 70 | } 71 | 72 | return 73 | } 74 | 75 | /* 76 | Clones the queue into a new object. 77 | */ 78 | func (q *Queue) Clone( ) ( cq *Queue ) { 79 | cid := *q.Id 80 | cexref := *q.exref 81 | 82 | cq = &Queue { 83 | bandwidth: q.bandwidth, 84 | Id: &cid, 85 | qnum: q.qnum, 86 | pri: q.pri, 87 | exref: &cexref, 88 | } 89 | 90 | return 91 | } 92 | 93 | /* 94 | Increase the amount assigned to the queue by amt. 95 | */ 96 | func (q *Queue) Inc( amt int64 ) { 97 | if q != nil { 98 | q.bandwidth += amt 99 | if q.bandwidth < 0 { 100 | q.bandwidth = 0 101 | } 102 | } 103 | } 104 | 105 | /* 106 | Decrease the amount assigned to the queue by amt. 107 | */ 108 | func (q *Queue) Dec( amt int64 ) { 109 | if q != nil { 110 | q.bandwidth -= amt 111 | if q.bandwidth < 0 { 112 | q.bandwidth = 0 113 | } 114 | } 115 | } 116 | 117 | /* 118 | Destruction 119 | */ 120 | func (q *Queue) Nuke() { 121 | if q != nil { 122 | q.Id = nil 123 | q.exref = nil 124 | } 125 | } 126 | 127 | /* 128 | Sets the bandwidh for the queue to the value (bps) passed in. 129 | */ 130 | func (q *Queue) Set_bandwidth( b int64 ) { 131 | if q != nil { 132 | q.bandwidth = b; 133 | } 134 | } 135 | 136 | /* 137 | Adjust the priority of the queue to the value passed in. 138 | Priority values should be between 1 and 1024 with the larger 139 | values being lower in priority. 140 | */ 141 | func (q *Queue) Set_priority( p int ) { 142 | if q != nil { 143 | q.pri = p; 144 | } 145 | } 146 | 147 | /* 148 | Returns the queue number for this queue. The queue number is the 149 | value that is placed on flow-mods which are sent to the switch 150 | as an enqueue action and that are associated with a min/max 151 | and/or QoS group on the switch. A value of -1 is returned 152 | on error. 153 | */ 154 | func (q *Queue) Get_num( ) ( int ) { 155 | if q != nil { 156 | return q.qnum; 157 | } 158 | 159 | return -1 160 | } 161 | 162 | /* 163 | Returns a pointer to the external reference string associated with this queue. 164 | */ 165 | func (q *Queue) Get_eref( ) ( *string ) { 166 | if q != nil { 167 | return q.exref 168 | } 169 | 170 | return nil 171 | } 172 | 173 | /* 174 | Genrate a string that can be given on a queue setting command line. 175 | Format is: ,,,,, 176 | For the moment, both min/max bandwidth are the same, but we'll allow for them to be different 177 | in future. 178 | */ 179 | func ( q *Queue ) To_str( ) ( string ) { 180 | 181 | if q == nil { 182 | return "" 183 | } 184 | 185 | st := fmt.Sprintf( "%s,%s,%d,%d,%d,%d", *q.exref, *q.Id, q.qnum, q.bandwidth, q.bandwidth, q.pri ); 186 | return st 187 | } 188 | 189 | /* 190 | Return a string only if bandwidth value is positive. 191 | */ 192 | func ( q *Queue ) To_str_pos( ) ( string ) { 193 | 194 | if q == nil || q.bandwidth <= 0 { 195 | return "" 196 | } 197 | 198 | st := fmt.Sprintf( "%s,%s,%d,%d,%d,%d", *q.exref, *q.Id, q.qnum, q.bandwidth, q.bandwidth, q.pri ); 199 | return st 200 | } 201 | 202 | /* 203 | Returns a json string that represents this queue. The information includes num, priority, 204 | bandwidh, id and external reference string. 205 | */ 206 | func (q *Queue) To_json( ) ( string ) { 207 | if q == nil { 208 | return "" 209 | } 210 | 211 | st := fmt.Sprintf( `{ "num": %d, "pri": %d, "bandw": %d, "id": %q, "eref": %q }`, q.qnum, q.pri, q.bandwidth, *q.Id, *q.exref ) 212 | 213 | return st 214 | } 215 | -------------------------------------------------------------------------------- /gizmos/spq.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: spq 24 | Abstract: A simple object that contains a switch (id/name), port and queue number. 25 | All are externally accessible and other than the constructor there are 26 | no functions that operate on this object. 27 | 28 | Date: 18 February 2013 29 | Author: E. Scott Daniels 30 | Mod: 11 Jun 2015 - corrected comment, removed uneeded import commented things. 31 | 32 | */ 33 | 34 | package gizmos 35 | 36 | import ( 37 | "fmt" 38 | 39 | //"github.com/att/gopkgs/clike" 40 | ) 41 | 42 | type Spq struct { 43 | Switch string 44 | Port int 45 | Queuenum int 46 | } 47 | 48 | 49 | 50 | // --------------------------------------------------------------------------------------- 51 | 52 | /* 53 | Creates a switch/port/queue representation for an endpoint. 54 | */ 55 | func Mk_spq( sw string, p int, q int ) (s *Spq) { 56 | s = &Spq { 57 | Switch: sw, 58 | Port: p, 59 | Queuenum: q, 60 | } 61 | 62 | return 63 | } 64 | 65 | func (s *Spq) String( ) ( string ) { 66 | if s == nil { 67 | return "==nil==" 68 | } 69 | 70 | return fmt.Sprintf( "spq: %s %d %d", s.Switch, s.Port, s.Queuenum ) 71 | } 72 | -------------------------------------------------------------------------------- /main/rjprt.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: rjprt.go 24 | Abstract: Send an http oriented post or get request that results in json output and 25 | then format the output in a human readable fashion to stdout. 26 | is returned. Input command line: 27 | -a token Authorisation token related to the privlege of executing the command 28 | such as listhost (not VM related tokens for a reservation). 29 | -d Display result in 'dotted' notaion rather than indented hiarchy 30 | -D POST request "body of data" 31 | -j No formatting, outputs raw json 32 | -J Send application/json as the type rather than application/text. 33 | -l path implies -d; looks for the 'path' in the result (e.g. root[0].mac[0]) 34 | -m method where method is POST or GET (GET is default) 35 | -r returns raw json (debugging mostly) 36 | -t url Target url 37 | -T tight security (does not trust host certificates that cannot be validated) 38 | -v verbose 39 | 40 | Date: 01 January 2014 41 | Author: E. Scott Daniels 42 | 43 | Mod: 07 Jun 2014 - Added ability to ignore invalid certs (-T option added to force tight security) 44 | 09 Jul 3014 - Added -J capability 45 | 14 Dec 2014 - Formally moved to tegu code. 46 | 03 Jun 2015 - To accept an authorisation token to send as X-Tegu-Auth in the header. 47 | 19 Jun 2015 - Added support to dump headers in order to parse out the token that openstack 48 | identity v3 sends back in the bloody header of all places. 49 | 24 Jun 2015 - Added xauth support to GET. 50 | */ 51 | 52 | package main 53 | 54 | import ( 55 | "bytes" 56 | "crypto/tls" 57 | "flag" 58 | "fmt" 59 | "io/ioutil" 60 | "net/http" 61 | "os" 62 | 63 | "github.com/att/gopkgs/jsontools" 64 | ) 65 | 66 | // global variables 67 | var ( 68 | ) 69 | 70 | func usage( version string ) { 71 | fmt.Printf( "%s\n", version ); 72 | fmt.Printf( "usage: rjprt [-a auth-string] [-D data-string] [-d] [-t target-url] [-j] [-J] [-l dot-string] [-m GET|POST|DELETE] [-r root-string] [-T] [-v] -t target url\n" ) 73 | fmt.Printf( ` If -m POST or -m DELETE is supplied, and -D "string" is omitted, rjprt will read the POST data from stdin` ) 74 | fmt.Printf( "\n\n" ) 75 | } 76 | 77 | func main() { 78 | var ( 79 | version string = "rjprt v1.4/16195" 80 | auth *string 81 | err error 82 | resp *http.Response 83 | verbose *bool 84 | root *string 85 | raw_json *bool 86 | needs_help *bool 87 | target_url *string 88 | dot_fmt *bool 89 | look4 *string 90 | method *string 91 | request_data *string 92 | req *http.Request 93 | ) 94 | 95 | needs_help = flag.Bool( "?", false, "show usage" ) 96 | 97 | auth = flag.String( "a", "", "authorisation token" ) 98 | dot_fmt = flag.Bool( "d", false, "dotted named output" ) 99 | request_data = flag.String( "D", "", "post data" ) 100 | raw_json = flag.Bool( "j", false, "raw-json" ) 101 | show_headers := flag.Bool( "h", false, "show http response headers" ) 102 | appl_json := flag.Bool( "J", false, "data type is json" ) 103 | look4 = flag.String( "l", "", "look4 string in hashtab" ) 104 | method = flag.String( "m", "GET", "request method" ) 105 | root = flag.String( "r", "", "top level root name" ) 106 | target_url = flag.String( "t", "", "target url" ) 107 | tight_sec := flag.Bool( "T", false, "tight security ON" ) 108 | verbose = flag.Bool( "v", false, "verbose" ) 109 | flag.Parse(); // actually parse the commandline 110 | 111 | input_type := "text" // type of data being sent in body 112 | if *appl_json { 113 | input_type = "application/json" 114 | } 115 | 116 | if *needs_help { 117 | usage( version ) 118 | os.Exit( 0 ) 119 | } 120 | 121 | if *look4 != "" { // -l imples -d 122 | *dot_fmt = true 123 | } 124 | 125 | if *target_url == "" { 126 | fmt.Fprintf( os.Stderr, "target url is missing from command line (use -t url)\n" ) 127 | os.Exit( 1 ) 128 | } 129 | 130 | if( *verbose ) { 131 | fmt.Fprintf( os.Stderr, "target=%s\n", *target_url ) 132 | } 133 | 134 | trparms := &http.Transport{ // override default transport parms to skip the verify 135 | TLSClientConfig: &tls.Config{ InsecureSkipVerify: !*tight_sec }, 136 | } 137 | 138 | client := &http.Client{ Transport: trparms } // default client except with our parms 139 | 140 | switch( *method ) { 141 | case "GET", "get": 142 | req, err = http.NewRequest( "GET", *target_url, nil ) 143 | if err == nil { 144 | if auth != nil && *auth != "" { 145 | req.Header.Set( "X-Auth-Tegu", *auth ) 146 | } 147 | 148 | resp, err = client.Do( req ) 149 | } 150 | 151 | case "POST", "post": 152 | if *request_data == "" { 153 | req, err = http.NewRequest( "POST", *target_url, os.Stdin ) 154 | } else { 155 | req, err = http.NewRequest( "POST", *target_url, bytes.NewBufferString( *request_data ) ) 156 | } 157 | 158 | if err == nil { 159 | req.Header.Set( "Content-Type", input_type ) 160 | if auth != nil && *auth != "" { 161 | req.Header.Set( "X-Auth-Tegu", *auth ) 162 | } 163 | 164 | resp, err = client.Do( req ) 165 | } 166 | 167 | case "DELETE", "del", "delete": 168 | if *request_data == "" { 169 | req, err = http.NewRequest( "DELETE", *target_url, os.Stdin ) 170 | } else { 171 | req, err = http.NewRequest( "DELETE", *target_url, bytes.NewBufferString( *request_data ) ) 172 | } 173 | 174 | if err == nil { 175 | if auth != nil && *auth != "" { 176 | req.Header.Add( "X-Auth-Tegu", *auth ) 177 | } 178 | resp, err = client.Do( req ) 179 | } 180 | 181 | default: 182 | fmt.Fprintf( os.Stderr, "%s method is not supported\n", *method ) 183 | os.Exit( 1 ) 184 | } 185 | 186 | if err != nil { 187 | fmt.Printf( "%s request failed: %s\n", *method, err ) 188 | os.Exit( 1 ) 189 | } else { 190 | data, err := ioutil.ReadAll( resp.Body ) 191 | if err != nil { 192 | fmt.Printf( "read of data from url failed\n" ) 193 | os.Exit( 1 ) 194 | } 195 | resp.Body.Close( ) 196 | 197 | if *show_headers { 198 | for k, v := range resp.Header { 199 | fmt.Printf( "header: %s = %s\n", k, v ) 200 | } 201 | } 202 | 203 | if data == nil { 204 | os.Exit( 0 ); // maybe not what they were expecting, but nothing isn't an error 205 | } 206 | 207 | if *raw_json { 208 | fmt.Printf( "%s\n", data ) 209 | os.Exit( 0 ) 210 | } 211 | 212 | if *dot_fmt { 213 | m, err := jsontools.Json2map( data, root, false ); // build the map 214 | if err == nil { 215 | if *look4 != "" { 216 | result := m[*look4] 217 | if result != nil { 218 | switch result.( type ) { 219 | case string: 220 | fmt.Printf( "%s = %s\n", *look4, result.(string) ) 221 | 222 | case int: 223 | fmt.Printf( "%s = %d\n", *look4, result.(int) ) 224 | 225 | case float64: 226 | fmt.Printf( "%s = %.2f\n", *look4, result.(float64) ) 227 | 228 | default: 229 | fmt.Printf( "found %s, but its in an unprintable format\n", *look4 ) 230 | } 231 | 232 | } else { 233 | fmt.Fprintf( os.Stderr, "didn't find: %s\n", *look4 ) 234 | } 235 | } else { 236 | jsontools.Print( m, *root, true ) 237 | } 238 | } else { 239 | fmt.Fprintf( os.Stderr, "ERR: %s \n", err ); 240 | } 241 | } else { 242 | _, err = jsontools.Json2blob( data, root, true ); // normal hiarchy can be printed as it blobs, so ignore jif coming back 243 | if err != nil { // assume mirroring which doesn't put out json in all cases (boo) 244 | //fmt.Fprintf( os.Stderr, "ERR: %s \n", err ); 245 | fmt.Fprintf( os.Stdout, "%s\n", data ); 246 | } 247 | } 248 | } 249 | 250 | os.Exit( 0 ) 251 | } 252 | 253 | -------------------------------------------------------------------------------- /managers/fq_pass.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | Mnemonic: fq_mgr_pass 23 | Abstract: flow/queue manager passthrough reservation related things. 24 | 25 | Date: 26 January 2016 26 | Author: E. Scott Daniels 27 | 28 | Mods: 29 | */ 30 | 31 | package managers 32 | 33 | import ( 34 | "encoding/json" 35 | 36 | "github.com/att/gopkgs/ipc" 37 | ) 38 | 39 | 40 | /* 41 | Send a passthrough flowmod generation request to the agent manager. 42 | This is basically taking the struct that the reservation manager 43 | filled in and converting it to a map. 44 | 45 | Send a bandwidth endpoint flow-mod request to the agent manager. 46 | This is little more than a wrapper that converts the fq_req into 47 | an agent request. The ultimate agent action is to put in all 48 | needed flow-mods on an endpoint host in one go, so no need for 49 | individual requests for each and no need for tegu to understand 50 | the acutal flow-mod mechanics any more. 51 | 52 | Yes, this probably _could_ be pushed up into the reservation manager 53 | and sent from there to the agent manager, but for now, since the 54 | ip2mac information is local to fq-mgr, we'll keep it here. (That 55 | info is local to fq-mgr b/c in the original Tegu it came straight 56 | in from skoogi and it was fq-mgr's job to interface with skoogi.) 57 | */ 58 | func send_pt_fmods( data *Fq_req, ip2mac map[string]*string, phost_suffix *string ) { 59 | 60 | 61 | if *data.Swid == "" { // we must have a switch name to set bandwidth fmods 62 | fq_sheep.Baa( 1, "unable to send passthrough fmod request to agent: no switch defined in input data" ) 63 | return 64 | } 65 | 66 | host := data.Swid 67 | if phost_suffix != nil { // we need to add the physical host suffix 68 | host = add_phost_suffix( host, phost_suffix ) 69 | } 70 | 71 | if data.Match.Smac != nil { // caller can pass in IP and we'll convert it 72 | if ip2mac[*data.Match.Smac] != nil { 73 | data.Match.Smac = ip2mac[*data.Match.Smac] // res-mgr thinks in IP, flow-mods need mac; convert 74 | } 75 | } 76 | 77 | msg := &agent_cmd{ Ctype: "action_list" } // create a message for agent manager to send to an agent 78 | msg.Actions = make( []action, 1 ) // just a single action 79 | msg.Actions[0].Atype = "passthru" // set all related passthrough flow-mods 80 | msg.Actions[0].Hosts = make( []string, 1 ) // passthrough flow-mods created on just one host 81 | msg.Actions[0].Hosts[0] = *host 82 | msg.Actions[0].Data = data.To_pt_map() // convert useful data from caller into parms for agent 83 | 84 | json, err := json.Marshal( msg ) // bundle into a json string 85 | if err != nil { 86 | fq_sheep.Baa( 0, "unable to build json to set passthrough flow-mods" ) 87 | } else { 88 | tmsg := ipc.Mk_chmsg( ) 89 | tmsg.Send_req( am_ch, nil, REQ_SENDSHORT, string( json ), nil ) // send as a short request to one agent 90 | } 91 | 92 | fq_sheep.Baa( 2, "passthru flow-mod request sent to agent manager: %s", json ) 93 | } 94 | -------------------------------------------------------------------------------- /managers/http_fetch.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: http_get 24 | Abstract: Module contains function(s) needed by the http_api manager to process get 25 | requests. 26 | 27 | Date: 10 December 2015 28 | Author: E. Scott Daniels 29 | 30 | Mods: 31 | */ 32 | 33 | package managers 34 | 35 | import ( 36 | "fmt" 37 | "io" 38 | "net/http" 39 | "os" 40 | "strings" 41 | "time" 42 | ) 43 | 44 | /* 45 | Deal with a get request, but not quite in the traditional manner. We expect 46 | the 'filename' to be a generic name and we'll determine where to locate the 47 | file (likely /usr/bin). The purpose of this is to allow a user to pull the 48 | rjprt and tegu_req programmes which were distributed with this version of 49 | Tegu, and not a general purporse http server. Thus we will only recognise 50 | specific filenames, and rject all other attempts to get something. 51 | */ 52 | func parse_get( out http.ResponseWriter, uri string, sender string, xauth string ) (state string, msg string) { 53 | 54 | dir := "/usr/bin" 55 | 56 | tokens := strings.Split( uri, "/" ) 57 | req_name := tokens[len( tokens )-1] 58 | 59 | fname := "" 60 | otype := "application/binary" 61 | switch req_name { // we only allow a fetch of just a few.... 62 | case "rjprt": 63 | fname = dir + "/" + req_name 64 | 65 | case "tegu_req": 66 | fname = dir + "/" + req_name 67 | 68 | default: 69 | hdr := out.Header() 70 | hdr.Add("Content-type", "text/html") 71 | out.WriteHeader( 401 ) 72 | now := time.Now(); 73 | fmt.Fprintf( out, ` %s sorry Charlie, not allowed` + "\n", now ); 74 | 75 | return "ERROR", "not allowed" 76 | } 77 | 78 | http_sheep.Baa( 1, "get sending file: %s", fname ) 79 | f, err := os.Open( fname ) 80 | count := 0 81 | if err == nil { 82 | defer f.Close() 83 | 84 | buffer := make( []byte, 4096 ) 85 | state = "OK"; 86 | msg = "ok"; 87 | 88 | hdr := out.Header() 89 | hdr.Add( "Content-type", otype ) 90 | 91 | for { 92 | nread, err := f.Read( buffer ) 93 | count += nread 94 | 95 | if err != nil { 96 | if err != io.EOF { 97 | http_sheep.Baa( 1, "get error reading file: %s: %s", fname, err ) 98 | } else { 99 | msg = fmt.Sprintf( "%d bytes transferred", count ) 100 | } 101 | return 102 | } 103 | 104 | if nread > 0 { 105 | _, err = out.Write( buffer[0:nread] ) 106 | if err != nil { 107 | http_sheep.Baa( 1, "get error writing file: %s: %s", fname, err ) 108 | msg = fmt.Sprintf( "%d bytes transferred", count ) 109 | return 110 | } 111 | } 112 | } 113 | } else { 114 | http_sheep.Baa( 1, "get error opening file: %s: %s", fname, err ) 115 | hdr := out.Header() 116 | hdr.Add("Content-type", "text/html") 117 | out.WriteHeader( 400 ) 118 | now := time.Now(); 119 | fmt.Fprintf( out, ` %s read error, unable to find: %s` + "\n", now, uri ); 120 | state = "ERROR"; 121 | msg = fmt.Sprintf( "cannot open file: %s: %s", fname, err ) 122 | return 123 | } 124 | 125 | state = "OK"; // shouldn't get here, but prevent bad things 126 | msg = "ok"; 127 | return; 128 | } 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /managers/mgr_tools.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: mgr_tools 24 | Abstract: A collection of functions that are shared across all management types in the package. 25 | 26 | Date: 08 June 2015 27 | Author: E. Scott Daniels 28 | 29 | Mods: 30 | */ 31 | 32 | package managers 33 | import ( 34 | "strings" 35 | ) 36 | 37 | 38 | import ( 39 | 40 | "github.com/att/gopkgs/bleater" 41 | "github.com/att/gopkgs/ipc" 42 | ) 43 | 44 | 45 | /* 46 | Send a request to openstack interface for a host list. We will _not_ wait on it 47 | and will handle the response in the main loop. 48 | */ 49 | func req_hosts( rch chan *ipc.Chmsg, sheep *bleater.Bleater ) { 50 | sheep.Baa( 2, "requesting host list from osif" ) 51 | 52 | req := ipc.Mk_chmsg( ) 53 | req.Send_req( osif_ch, rch, REQ_CHOSTLIST, nil, nil ) 54 | } 55 | 56 | /* 57 | Given a VM name of the form project/stuff, or just stuff, return stuff. 58 | */ 59 | func strip_project( name *string ) ( *string ) { 60 | 61 | if name == nil { 62 | return nil 63 | } 64 | 65 | toks := strings.SplitN( *name, "/", 2 ) 66 | if len( toks ) < 2 { // no project id in the name, assume just IP 67 | return name 68 | } 69 | 70 | return &toks[1] 71 | } 72 | 73 | /* 74 | Gathers information about the host from openstack, and if known inserts the information into 75 | the network graph. If block is true, then we will block on a repl from network manager. 76 | If update_fqmgr is true, then we will also send osif a request to update the fqmgr with 77 | data that might ahve changed as a result of lazy gathering of info by the get_hostinfo 78 | request. If block is set, then we block until osif acks the request. This ensures 79 | that the request has been given to fq-mgr which is single threaded and thus will process 80 | the update before attempting to process any flow-mods that result from a later reservation. 81 | */ 82 | func update_graph( hname *string, update_fqmgr bool, block bool ) { 83 | 84 | my_ch := make( chan *ipc.Chmsg ) // allocate channel for responses to our requests 85 | 86 | req := ipc.Mk_chmsg( ) 87 | req.Send_req( osif_ch, my_ch, REQ_GET_HOSTINFO, hname, nil ) // request data 88 | req = <- my_ch 89 | if req.Response_data != nil { // if returned send to network for insertion 90 | if ! block { 91 | my_ch = nil // turn off if not blocking 92 | } 93 | 94 | req.Send_req( nw_ch, my_ch, REQ_ADD, req.Response_data, nil ) // add information to the graph 95 | if block { 96 | _ = <- my_ch // wait for response -- at the moment we ignore 97 | } 98 | } else { 99 | if req.State != nil { 100 | http_sheep.Baa( 2, "unable to get host info for %s: %s", *hname, req.State ) // this is probably ok as it's likely a !//ipaddress hostname, but we'll log it anyway 101 | } 102 | } 103 | 104 | if update_fqmgr { 105 | req := ipc.Mk_chmsg( ) 106 | req.Send_req( osif_ch, my_ch, REQ_IP2MACMAP, hname, nil ) // cause osif to push changes into fq-mgr (caution: we give osif fq-mgr's channel for response) 107 | if block { 108 | _ = <- my_ch 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /managers/net_req.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | Mnemonic: net_req.go 23 | Abstract: Functions that manage net_req struct. 24 | Date: 16 November 2014 25 | Author: E. Scott Daniels 26 | 27 | Mods: 27 Feb 2015 - Changes to make steering work with lazy update. 28 | 31 Mar 2015 - Changes to provide a force load of all VMs into the network graph. 29 | */ 30 | 31 | package managers 32 | 33 | import ( 34 | "github.com/att/gopkgs/ipc" 35 | ) 36 | 37 | type Net_vm struct { 38 | name *string 39 | id *string // openstack assigned id 40 | ip4 *string // openstack assigned ip address 41 | ip6 *string // openstack assigned ip address 42 | phost *string // phys host where vm is running 43 | mac *string // MAC 44 | gw *string // the gateway associated with the VM (if known) 45 | fip *string // floating ip 46 | gwmap map[string]*string // the gateway information associated with the VM (obsolete) 47 | } 48 | 49 | /* 50 | Create a vm insertion structure. Not a good idea to create a nil named structure, but 51 | we'll allow it and subs in the ip4 value as its name if provided, otherwise the string unnamed. 52 | */ 53 | func Mk_netreq_vm( name *string, id *string, ip4 *string, ip6 *string, phost *string, mac *string, gw *string, fip *string, gwmap map[string]*string ) ( np *Net_vm ) { 54 | if name == nil { 55 | if ip4 != nil { // no name, use ip4 if there 56 | name = ip4 57 | } else { 58 | unv := "unnamed" 59 | name = &unv 60 | } 61 | } 62 | 63 | np = &Net_vm { 64 | name: name, 65 | id: id, 66 | ip4: ip4, 67 | ip6: ip6, 68 | phost: phost, 69 | mac: mac, 70 | gw: gw, 71 | fip: fip, 72 | gwmap: gwmap, // we assume the map is ours to keep 73 | } 74 | 75 | return 76 | } 77 | 78 | /* 79 | Returns all values except the gateway map. 80 | */ 81 | func (vm *Net_vm) Get_values( ) ( name *string, id *string, ip4 *string, ip6 *string, gw *string, phost *string, mac *string, fip *string ) { 82 | if vm == nil { 83 | return 84 | } 85 | 86 | return vm.name, vm.id, vm.ip4, vm.ip6, vm.phost, vm.gw, vm.mac, vm.fip 87 | } 88 | 89 | /* 90 | Returns the map. 91 | */ 92 | func (vm *Net_vm) Get_gwmap() ( map[string]*string ) { 93 | return vm.gwmap 94 | } 95 | 96 | /* 97 | Replaces the name in the struct with the new value if nv isn't nil; 98 | */ 99 | func (vm *Net_vm) Put_name( nv *string ) { 100 | if vm != nil && nv != nil { 101 | vm.name = nv 102 | } 103 | } 104 | 105 | /* 106 | Replaces the id with the new value 107 | */ 108 | func (vm *Net_vm) Put_id( nv *string ) { 109 | if vm != nil { 110 | vm.id = nv 111 | } 112 | } 113 | 114 | /* 115 | Replaces the id with the new value 116 | */ 117 | func (vm *Net_vm) Put_ip4( nv *string ) { 118 | if vm != nil { 119 | vm.ip4 = nv 120 | } 121 | } 122 | 123 | /* 124 | Replaces the id with the new value 125 | */ 126 | func (vm *Net_vm) Put_ip6( nv *string ) { 127 | if vm != nil { 128 | vm.ip6 = nv 129 | } 130 | } 131 | 132 | /* 133 | Replace the physical host with the supplied value. 134 | */ 135 | func (vm *Net_vm) Put_phost( nv *string ) { 136 | if vm != nil { 137 | vm.phost = nv 138 | } 139 | } 140 | 141 | /* 142 | Send the vm struct to network manager as an insert to it's maps 143 | */ 144 | func (vm *Net_vm) Add2graph( nw_ch chan *ipc.Chmsg ) { 145 | 146 | msg := ipc.Mk_chmsg( ) 147 | msg.Send_req( nw_ch, nil, REQ_ADD, vm, nil ) 148 | } 149 | 150 | /* 151 | Output in human readable form. 152 | */ 153 | func (vm *Net_vm) To_str() ( string ) { 154 | if vm == nil { 155 | return "" 156 | } 157 | 158 | str := "" 159 | if vm.name != nil { 160 | str = str + *vm.name + " " 161 | } else { 162 | str = str + " " 163 | } 164 | if vm.id != nil { 165 | str = str + *vm.id + " " 166 | } else { 167 | str = str + " " 168 | } 169 | if vm.ip4 != nil { 170 | str = str + *vm.ip4 + " " 171 | } else { 172 | str = str + " " 173 | } 174 | if vm.ip6 != nil { 175 | str = str + *vm.ip6 + " " 176 | } else { 177 | str = str + " " 178 | } 179 | if vm.phost != nil { 180 | str = str + *vm.phost + " " 181 | } else { 182 | str = str + " " 183 | } 184 | if vm.gw != nil { 185 | str = str + *vm.gw + " " 186 | } else { 187 | str = str + " " 188 | } 189 | if vm.mac != nil { 190 | str = str + *vm.mac + " " 191 | } else { 192 | str = str + " " 193 | } 194 | if vm.fip != nil { 195 | str = str + *vm.fip 196 | } else { 197 | str = str + "" 198 | } 199 | 200 | return str 201 | } 202 | -------------------------------------------------------------------------------- /managers/res_mgr_mirror.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | Mnemonic: res_mgr_mirror 23 | Abstract: Reservation manager functions that are directly related to mirroring. 24 | 25 | Author: Robert Eby 26 | 27 | Mods: 23 Feb 2015 - Created. 28 | 26 May 2015 - Changes to support pledge as an interface. 29 | 16 Nov 2015 - Add save_mirror_response() 30 | 24 Nov 2015 - Add options 31 | */ 32 | 33 | package managers 34 | 35 | import ( 36 | "fmt" 37 | "regexp" 38 | "strings" 39 | "github.com/att/gopkgs/ipc" 40 | "github.com/att/tegu/gizmos" 41 | ) 42 | 43 | /* 44 | * Push an "add mirror" request out to an agent in order to create the mirror. 45 | */ 46 | func push_mirror_reservation( gp *gizmos.Pledge, rname string, ch chan *ipc.Chmsg ) { 47 | 48 | p, ok := (*gp).( *gizmos.Pledge_mirror ) // better be a mirroring pledge 49 | if ! ok { 50 | rm_sheep.Baa( 1, "internal error: pledge passed to push_mirror_reservations wasn't a mirror pledge" ) 51 | (*gp).Set_pushed() // prevent looping until it expires 52 | return 53 | } 54 | 55 | ports, out, _, _, _, _, _, _ := p.Get_values( ) 56 | ports2 := strings.Replace(*ports, " ", ",", -1) // ports must be comma separated 57 | 58 | // This is somewhat of a hack, but as long as the code in tegu_agent:do_mirrorwiz doesn't change, it should work 59 | id := p.Get_id( ) 60 | arg := *id 61 | opts := p.Get_Options() 62 | if opts != nil && *opts != "" { 63 | arg = fmt.Sprintf("-o%s %s", *opts, *id) 64 | } 65 | 66 | host := p.Get_qid( ) 67 | rm_sheep.Baa( 1, "Adding mirror %s on host %s", *id, *host ) 68 | json := `{ "ctype": "action_list", "actions": [ { ` 69 | json += `"atype": "mirrorwiz", ` 70 | json += fmt.Sprintf(`"hosts": [ %q ], `, *host) 71 | if strings.Contains(ports2, ",vlan:") { 72 | // Because we have to store the ports list and the vlans in the same field 73 | // we split it out here 74 | n := strings.Index(ports2, ",vlan:") 75 | vlan := ports2[n+6:] 76 | ports2 = ports2[:n] 77 | json += fmt.Sprintf(`"qdata": [ "add", %q, %q, %q, %q ] `, arg, ports2, *out, vlan) 78 | } else { 79 | json += fmt.Sprintf(`"qdata": [ "add", %q, %q, %q ] `, arg, ports2, *out) 80 | } 81 | json += `} ] }` 82 | rm_sheep.Baa( 2, " JSON -> %s", json ) 83 | msg := ipc.Mk_chmsg( ) 84 | msg.Send_req( am_ch, nil, REQ_SENDSHORT, json, nil ) // send this as a short request to one agent 85 | p.Set_pushed() 86 | } 87 | 88 | /* 89 | * Push a "delete mirror" request out to an agent in order to remove the mirror. 90 | */ 91 | func undo_mirror_reservation( gp *gizmos.Pledge, rname string, ch chan *ipc.Chmsg ) { 92 | 93 | p, ok := (*gp).( *gizmos.Pledge_mirror ) // better be a mirroring pledge 94 | if ! ok { 95 | rm_sheep.Baa( 1, "internal error: pledge passed to undo_mirror_reservations wasn't a mirror pledge" ) 96 | (*gp).Set_pushed() // prevent looping until it expires 97 | return 98 | } 99 | 100 | id := p.Get_id( ) 101 | // This is somewhat of a hack, but as long as the code in tegu_agent:do_mirrorwiz doesn't change, it should work 102 | arg := *id 103 | opts := p.Get_Options() 104 | if opts != nil && *opts != "" { 105 | arg = fmt.Sprintf("-o%s %s", *opts, *id) 106 | } 107 | 108 | host := p.Get_qid( ) 109 | rm_sheep.Baa( 1, "Deleting mirror %s on host %s", *id, *host ) 110 | json := `{ "ctype": "action_list", "actions": [ { ` 111 | json += `"atype": "mirrorwiz", ` 112 | json += fmt.Sprintf(`"hosts": [ %q ], `, *host) 113 | json += fmt.Sprintf(`"qdata": [ "del", %q ] `, arg) 114 | json += `} ] }` 115 | rm_sheep.Baa( 2, " JSON -> %s", json ) 116 | msg := ipc.Mk_chmsg( ) 117 | msg.Send_req( am_ch, nil, REQ_SENDSHORT, json, nil ) // send this as a short request to one agent 118 | p.Set_pushed() 119 | } 120 | 121 | /* 122 | * Save the returned response from an agent into the mirror pledge. This is a gigantic hack, 123 | * but the present design of the agents doesn't provide an easy way to do this. 124 | */ 125 | func save_mirror_response( stdout []string, stderr []string ) { 126 | // Try to figure out which mirror these responses are for. 127 | // Look for a valid mirror name in any output 128 | re := regexp.MustCompile(`mir-[0-9a-f]{8}_[0-9]`) 129 | for _, s := range append(stdout, stderr...) { 130 | name := re.FindString(s) 131 | if name != "" { 132 | // Fetch the mirror and save the stdout/err 133 | m := lookupMirror( name, *super_cookie ) 134 | if m != nil { 135 | rm_sheep.Baa( 1, "Saving output for mirror %s", name ) 136 | m.Set_Output( stdout, stderr ) 137 | } 138 | return 139 | } 140 | } 141 | rm_sheep.Baa( 1, "save_mirror_response: could not find the mirror name" ) 142 | } 143 | -------------------------------------------------------------------------------- /managers/res_mgr_pt.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | /* 22 | 23 | Mnemonic: res_mgr_pt 24 | Abstract: Functions which apply only to the passthrough reservations. 25 | 26 | Date: 26 January 2016 27 | Author: E. Scott Daniels 28 | 29 | Mods: 30 | */ 31 | 32 | package managers 33 | 34 | import ( 35 | "time" 36 | 37 | "github.com/att/gopkgs/ipc" 38 | "github.com/att/tegu/gizmos" 39 | ) 40 | 41 | /* 42 | For a single passthrough pledge, this function sets things up and sends needed requests to the fq-manger to 43 | create any necessary flow-mods. 44 | 45 | We send the following information to fq_mgr: 46 | source mac or endpoint (VM-- the host in the pledge) 47 | source IP and optionally port and protocol more specific reservations 48 | expiry 49 | switch (physical host -- compute node) 50 | 51 | Errors are returned to res_mgr via channel, but asycnh; we do not wait for responses to each message 52 | generated here. 53 | 54 | To_limit is a cap to the expiration time sent when creating a flow-mod. OVS (and others we assume) 55 | use an unsigned int32 as a hard timeout value, and thus have an upper limit of just over 18 hours. If 56 | to_limit is > 0, we'll ensure that the timeout passed on the request to fq-mgr won't exceed the limit, 57 | and we assume that this function is called periodically to update long running reservations. 58 | */ 59 | func pass_push_res( gp *gizmos.Pledge, rname *string, ch chan *ipc.Chmsg, to_limit int64 ) { 60 | var ( 61 | msg *ipc.Chmsg 62 | ) 63 | 64 | now := time.Now().Unix() 65 | 66 | p, ok := (*gp).( *gizmos.Pledge_pass ) // generic pledge better be a passthrough pledge! 67 | if ! ok { 68 | rm_sheep.Baa( 1, "internal error in pass_push_reservation: pledge isn't a passthrough pledge" ) 69 | (*gp).Set_pushed() // prevent looping 70 | return 71 | } 72 | 73 | host, _, _, expiry, proto := p.Get_values( ) // reservation info that we need 74 | 75 | ip := name2ip( host ) 76 | 77 | if ip != nil { // good ip addresses so we're good to go 78 | freq := Mk_fqreq( rname ) // default flow mod request with empty match/actions (for bw requests, we don't need priority or such things) 79 | freq.Match.Smac = ip // fq_mgr has conversion map to convert to mac 80 | freq.Swid = p.Get_phost() // the phyiscal host where the VM lives and where fmods need to be deposited 81 | 82 | freq.Cookie = 0xffff // should be ignored, if we see this out there we've got problems 83 | 84 | if (*p).Is_paused( ) { 85 | freq.Expiry = time.Now().Unix( ) + 15 // if reservation shows paused, then we set the expiration to 15s from now which should force the flow-mods out 86 | } else { 87 | if to_limit > 0 && expiry > now + to_limit { 88 | freq.Expiry = now + to_limit // expiry must be capped so as not to overflow virtual switch variable size 89 | } else { 90 | freq.Expiry = expiry 91 | } 92 | } 93 | freq.Id = rname 94 | 95 | freq.Extip = &empty_str 96 | 97 | // this will change when ported to endpoint branch as the endpoint allows address and port 'in line' 98 | freq.Match.Ip1 = proto // the proto on the reservation should be [{udp|tcp:}]address[:port] 99 | freq.Match.Ip2 = nil 100 | freq.Espq = nil 101 | dup_str := "" 102 | freq.Exttyp = &dup_str 103 | 104 | rm_sheep.Baa( 1, "pushing passthru reservation: %s", p ) 105 | msg = ipc.Mk_chmsg() 106 | msg.Send_req( fq_ch, ch, REQ_PT_RESERVE, freq, nil ) // queue work with fq-manger to read the struct and send cmd(s) to agent to get it done 107 | 108 | p.Set_pushed() // safe to mark the pledge as having been pushed. 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /managers/xmanagers_test.go: -------------------------------------------------------------------------------- 1 | // vi: sw=4 ts=4: 2 | /* 3 | --------------------------------------------------------------------------- 4 | Copyright (c) 2013-2015 AT&T Intellectual Property 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at: 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | --------------------------------------------------------------------------- 18 | */ 19 | 20 | 21 | 22 | package managers_test 23 | 24 | import "testing" 25 | import "fmt" 26 | import "os" 27 | 28 | 29 | func TestMan_util( t *testing.T ) { 30 | str = "udp:42" 31 | pv, port = managers.proto2val_port( &str ) 32 | fmt.Fprintf( os.Stderr, "%d %d\n", pv, port ) 33 | } 34 | 35 | -------------------------------------------------------------------------------- /system/crontab.qlite: -------------------------------------------------------------------------------- 1 | # crontab for qos-lite 2 | # 3 | MAILTO="" 4 | TEGU_ROOT=/var 5 | # 6 | # --- clean up log files and straggling data files from /tmp ------ 7 | 5 * * * * find /tmp -name "*tegu_setq_*" -mtime +1 -exec rm {} \; >$TEGU_ROOT/log/tegu/tmp_cleanup 2>&1 8 | 5 * * * * find $TEGU_ROOT/log/tegu -mtime +30 -exec rm {} \; >$TEGU_ROOT/log/tegu/log_cleanup 2>&1 9 | # 10 | # --- copy chckpoint information to standby hosts ---- 11 | */1 * * * * tegu_synch >$TEGU_ROOT/log/tegu/synch.log 2>&1 12 | 13 | -------------------------------------------------------------------------------- /system/ql_snuff.ksh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ksh 2 | # vi: sw=4 ts=4: 3 | # 4 | # --------------------------------------------------------------------------- 5 | # Copyright (c) 2013-2015 AT&T Intellectual Property 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at: 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # --------------------------------------------------------------------------- 19 | # 20 | 21 | # 22 | # Mnemonic: ql_snuff 23 | # Abstract: Snuff out all of the underlying things (fmods, queues, iptables rules) that 24 | # exist to support QoS-Lite. This should be exectued only as a last ditch effort 25 | # when you think that qlite is causing so many problms that you want to pull the 26 | # plug and let it all go down the drain. 27 | # 28 | # Date: 12 Feb 2014 29 | # Author: E. Scott Daniels 30 | # 31 | # Mod: 29 Oct 2015 - added 0xb0ff cookie to the list of flow-mods to the list. 32 | # -------------------------------------------------------------------------------------------------- 33 | 34 | trap "rm -f /tmp/PID$$.*" 1 2 3 15 EXIT 35 | 36 | function verify_id 37 | { 38 | whoiam=$( id -n -u ) 39 | if [[ $whoiam != $tegu_user ]] 40 | then 41 | echo "Only the tegu user ($tegu_user) can affect the state; ($(whoami) is not acceptable) [FAIL]" 42 | echo "'sudo su $tegu_user' and rerun this script" 43 | echo "" 44 | exit 1 45 | fi 46 | } 47 | 48 | function tty_rewrite 49 | { 50 | echo "$(date) $1" >>$log 51 | if (( ! agent_driven )) 52 | then 53 | printf "\r\033[0K%s" "$1" 54 | fi 55 | } 56 | 57 | 58 | 59 | # Delete the iptables rules in mangle that do the right thing for our DSCP marked traffic 60 | # This must also handle all of the bloody routers that are created in namespaces, so we first generate a 61 | # set of commands for the main iptables, then generate the same set for each nameespace. This all goes 62 | # into a single command file which is then fed into ssh to be executed on the target host. 63 | # 64 | # we assume that this funciton is run asynch and so we capture all output into a file that can be spit out 65 | # at the end. 66 | function purge_iptables 67 | { 68 | typeset cmd_string="" # normall space iptables command list 69 | typeset cmd_file=/tmp/PID$$.cmds # cmds to send to the remote to set ip stuff 70 | typeset nslist="/tmp/PID$$.nslist" # list of name spaces from the remote host 71 | typeset err_file="/tmp/PID$$.ipterr" 72 | typeset diffserv="184 104 72" # these MUST be 4x the DSCP values 73 | 74 | thost="$1" 75 | 76 | timeout 300 $ssh_cmd ip netns list >$nslist 2>$err_file 77 | if (( $? != 0 )) 78 | then 79 | echo "unable to get network name space list from target-host: ${thost#* } [FAIL]" >&2 80 | sed 's/^/purge_iptables:/' $err_file >&2 81 | return 1 82 | fi 83 | 84 | typeset iptables_del_base="sudo iptables -f -D POSTROUTING -t mangle -m dscp --dscp" # various pieces of the command string 85 | typeset iptables_tail="-j CLASSIFY --set-class" 86 | 87 | typeset iptables_nsbase="sudo ip netns exec" # must insert name space name between base and mid 88 | typeset iptables_del_mid="iptables -f -D POSTROUTING -t mangle -m dscp --dscp" # reset for the name space specific command 89 | 90 | ( # create the commands to send; first the master iptables rules, then rules for each name space 91 | echo "$iptables_del_base 0 $iptables_tail 1:2;" 92 | for d in ${diffserv//,/ } # d will be 4x the value that iptables needs 93 | do 94 | echo "$iptables_del_base $((d/4)) $iptables_tail 1:6;" # add in delete commands 95 | done 96 | 97 | while read ns # for each name space we found 98 | do 99 | echo "$iptables_nsbase $ns $iptables_del_mid 0 $iptables_tail 1:2;" # odd ball delete case first 100 | for d in ${diffserv//,/ } 101 | do 102 | echo "$iptables_nsbase $ns $iptables_del_mid $((d/4)) $iptables_tail 1:6;" # add in delete commands 103 | done 104 | done <$nslist 105 | ) >$cmd_file 106 | 107 | if [[ -z $thost || $thost == "localhost" ]] # local host -- just pump into ksh 108 | then 109 | ssh_host="ksh" 110 | else 111 | typeset ssh_cmd="ssh -T $ssh_opts $thost" # different than what we usually use NO -n supplied!! 112 | fi 113 | 114 | rc=0 # overall return code 115 | if [[ -z $really ]] # empty string means we're live 116 | then 117 | $forreal timeout 100 $ssh_cmd <$cmd_file >$err_file 2>&1 118 | rc=$? 119 | if (( rc != 0 )) 120 | then 121 | if ! grep -q "No chain/target/match by that name" $err_file # not an error; it wasn't there to begin with 122 | then 123 | echo "unable to purge iptables on target-host: ${thost#* } [FAIL]" >&2 124 | sed 's/^/purge_iptables:/' $err_file >&2 125 | else 126 | rc=0 127 | echo "iptables deleted for mangle rules on target-host: ${thosts#* }" >&2 128 | fi 129 | else 130 | echo "iptables deleted for mangle rules on target-host: ${thosts#* }" >&2 131 | fi 132 | else 133 | sed "s/^/iptables purge: $no_exec_str /" $cmd_file >&2 134 | fi 135 | 136 | rm -f /tmp/PID$$.* 137 | return $rc 138 | } 139 | 140 | 141 | # -------------------------------------------------------------------------------------------------- 142 | 143 | export TEGU_ROOT=${TEGU_ROOT:-/var} 144 | logd=${TEGU_LOGD:-/var/log/tegu} 145 | libd=${TEGU_LIBD:-/var/lib/tegu} 146 | etcd=${TEGU_ETCD:-/etc/tegu} 147 | chkptd=$TEGU_ROOT/chkpt 148 | tegu_user=${TEGU_USER:-tegu} 149 | 150 | ssh_opts="-o StrictHostKeyChecking=no -o PreferredAuthentications=publickey" 151 | log=/tmp/qlite_snuff.log 152 | 153 | really="-n" 154 | forreal="echo would run:" 155 | do_iptables=1 156 | do_fmods=1 157 | do_queues=1 158 | 159 | agent_driven=0 160 | 161 | while [[ $1 == -* ]] 162 | do 163 | case $1 in 164 | -a) agent_driven=1;; 165 | -F) do_fmods=0;; 166 | -Q) do_queues=0;; 167 | -I) do_iptables=0;; 168 | 169 | -b) only_bridges="$2"; shift;; 170 | -f) really=""; forreal="";; 171 | -p) >$log;; 172 | -n) really="-n" 173 | forreal="echo would run:" 174 | ssh_cmd="ssh $ssh_opts $h " 175 | ;; 176 | 177 | -*) echo "unrecognised option: $1" 178 | echo "usage: $0 [-p] [-b bridges] [-f] [-n] host1 [host2....hostn]" 179 | exit 1 180 | esac 181 | 182 | shift 183 | done 184 | 185 | host_list="$@" 186 | # remove flow-mods 187 | echo "removing flow-mods" 188 | 189 | fcount=0 190 | fecount=0 191 | qcount=0 192 | qecount=0 193 | icount=0 194 | iecount=0 195 | hcount=0 196 | 197 | for h in ${host_list:-localhost} 198 | do 199 | (( hcount++ )) 200 | if [[ $h == "localhost" ]] 201 | then 202 | target="" # no target for queues 203 | else 204 | target="-h $h" # running remotely we must pass it along this way 205 | fi 206 | 207 | if (( do_fmods )) 208 | then 209 | if [[ -z $only_bridges ]] 210 | then 211 | blist=$( $ssh_cmd sudo ovs-vsctl show | grep Bridge | awk ' { gsub( "\"", "", $0 ); l = l $2 " " } END { print l } ' ) 212 | else 213 | blist="$only_bridges" 214 | fi 215 | 216 | for b in $blist 217 | do 218 | for cookie in 0xbeef 0xdead 0xe5d 0xdeaf 0xfeed 0xface 0xb0ff 219 | do 220 | tty_rewrite "$h remove fmods: $b $cookie" 221 | send_ovs_fmod $really -h ${h:-nohost} -t 2 --match --action del $cookie $b >>$log 2>&1 222 | if (( $? != 0 )) 223 | then 224 | (( fecount++ )) 225 | printf "$(date) ... failed\n" 226 | printf "FAILED\n\n" >>$log 227 | fi 228 | 229 | (( fcount++ )) 230 | done 231 | done 232 | fi 233 | 234 | if (( do_queues )) 235 | then 236 | tty_rewrite "$h purging queues" 237 | purge_ovs_queues $really -a $target >>$log 2>&1 238 | if (( $? != 0 )) 239 | then 240 | (( qecount++ )) 241 | printf "$(date) ... failed\n" 242 | printf "FAILED\n\n" >>$log 243 | fi 244 | (( qcount++ )) 245 | fi 246 | 247 | if (( do_iptables )) 248 | then 249 | tty_rewrite "$h removing iptables rules" 250 | purge_iptables $h >>$log 2>&1 251 | if (( $? != 0 )) 252 | then 253 | (( iecount++ )) 254 | printf "$(date) ... failed\n" 255 | printf "FAILED\n\n" >>$log 256 | fi 257 | (( icount++ )) 258 | fi 259 | done 260 | 261 | tty_rewrite "" 262 | printf "hosts: %4d\n" "$hosts" 263 | printf "fmod purges: %4d\n" "$fcount" 264 | printf "fmod errors: %4d\n" "$fecount" 265 | printf "queue purges: %4d\n" "$qcount" 266 | printf "queue errors: %4d\n" "$qecount" 267 | printf "iptables purges: %4d\n" "$icount" 268 | printf "iptables errors: %4d\n" "$iecount" 269 | 270 | if (( agent_driven )) 271 | then 272 | cat $log >&2 273 | fi 274 | 275 | exit 0 276 | 277 | -------------------------------------------------------------------------------- /system/start_tegu_agent.ksh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ksh 2 | # vi: sw=4 ts=4: 3 | # 4 | # --------------------------------------------------------------------------- 5 | # Copyright (c) 2013-2015 AT&T Intellectual Property 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at: 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # --------------------------------------------------------------------------- 19 | # 20 | 21 | # 22 | # Mnemonic: start_agent 23 | # Abstract: Simple diddy to start the tegu_agent pointing at the proper spots for log and such. 24 | # By default the lib and log directories are assumed to be in /var/lib/tegu and /var/log/tegu 25 | # however these can be overridden with TEGU_LOGD and TEGU_LIBD environment variables if 26 | # necessary. 27 | # Date: 05 May 2014 28 | # Author: E. Scott Daniels 29 | # 30 | # Mod: 24 Jul 2014 - Support for standby host 31 | # -------------------------------------------------------------------------------------------------- 32 | 33 | export TEGU_ROOT=${TEGU_ROOT:-/var} 34 | logd=${TEGU_LOGD:-/var/log/tegu} 35 | libd=${TEGU_LIBD:-/var/lib/tegu} 36 | etcd=${TEGU_ETCD:-/etc/tegu} 37 | tegu_user=${TEGU_USER:-tegu} 38 | 39 | standby_file=$etcd/standby 40 | 41 | if [[ -f $standby_file ]] 42 | then 43 | echo "not starting agents -- this is a standby host [WARN]" 44 | echo "execute 'tegu_standby off' to turn stand-by mode off and then attempt to start with $0" 45 | exit 0 46 | fi 47 | 48 | if ! cd $logd 49 | then 50 | if ! mkdir $logd 51 | then 52 | echo "unable to find or mk $logd [FAIL]" 53 | exit 1 54 | fi 55 | fi 56 | 57 | whoiam=$( id -n -u ) 58 | if [[ $whoiam != $tegu_user ]] 59 | then 60 | echo "tegu_agent must be started under the user name tegu ($(whoami) is not acceptable) [FAIL]" 61 | echo '`sudo su tegu` and rerun this script' 62 | echo "" 63 | exit 1 64 | fi 65 | 66 | # all of these must be in the path or the agent cannot drive them, so verify now before starting agent(s) 67 | error=0 68 | for p in map_mac2phost setup_ovs_intermed create_ovs_queues ovs_sp2uuid send_ovs_fmod tegu_req purge_ovs_queues 69 | do 70 | if ! which $p >/dev/null 2>&1 71 | then 72 | error=1 73 | echo "CRI: unable to find programme/script in path: $p [FAIL]" 74 | fi 75 | done 76 | 77 | if (( error )) 78 | then 79 | exit 1 80 | fi 81 | 82 | 83 | # start n agents or the agents listed on the command line if not null 84 | if [[ -z $1 ]] 85 | then 86 | set 1 2 3 4 5 87 | fi 88 | 89 | while [[ -n $1 ]] 90 | do 91 | ps -elf|grep -q "tegu_agent [-]i $1" 92 | if (( $? > 0 )) 93 | then 94 | echo "staring tegu_agent $1 [OK]" 95 | nohup tegu_agent -i $1 -l $logd >tegu_agent$1.std 2>&1 & 96 | else 97 | echo "tegu_agent $1 is already running, not started [OK]" 98 | fi 99 | 100 | shift 101 | done 102 | exit 0 103 | -------------------------------------------------------------------------------- /system/start_tegu_ha.ksh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ksh 2 | # vi: sw=4 ts=4: 3 | # 4 | # --------------------------------------------------------------------------- 5 | # Copyright (c) 2013-2015 AT&T Intellectual Property 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at: 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # --------------------------------------------------------------------------- 19 | # 20 | 21 | # 22 | # Mnemonic: start_tegu_ha 23 | # Abstract: Simple wrapper script to start the tegu_ha daemon and to ensure that 24 | # multiple daemons aren't running. 25 | # Date: 30 Jan 2015 26 | # Author: E. Scott Daniels 27 | # 28 | # Mod: 29 | # -------------------------------------------------------------------------------------------------- 30 | 31 | export TEGU_ROOT=${TEGU_ROOT:-/var} 32 | logd=${TEGU_LOGD:-$TEGU_ROOT/log/tegu} 33 | libd=${TEGU_LIBD:-$TEGU_ROOT/lib/tegu} 34 | etcd=${TEGU_ETCD:-/etc/tegu} 35 | tegu_user=${TEGU_USER:-tegu} 36 | 37 | if [[ -s $libd/ha_pid ]] # check to see if it's still running 38 | then 39 | head -1 $libd/ha_pid | read pid 40 | ps -elf|grep tegu_ha | while read f1 f2 f3 f4 jrest 41 | do 42 | if [[ $f4 == $pid ]] 43 | then 44 | echo "tegu_ha appears to be running; not restarted [OK]" >&2 45 | exit 0 46 | fi 47 | done 48 | 49 | echo "tegu_ha with process id $pid wasn't found in system.... starting [OK]" >&2 50 | fi 51 | 52 | 53 | nohup tegu_ha >$logd/tegu_ha.log 2>&1 & 54 | pid=$! 55 | echo "$pid" >$libd/ha_pid 56 | echo "tegu_ha was started, pid=$pid" 57 | 58 | exit 0 59 | -------------------------------------------------------------------------------- /system/tegu_rc.ksh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # vi: sw=4 ts=4: 3 | # 4 | # --------------------------------------------------------------------------- 5 | # Copyright (c) 2013-2015 AT&T Intellectual Property 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at: 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # --------------------------------------------------------------------------- 19 | # 20 | 21 | # Mnemonic: tegu.rc.ksh 22 | # Abstract: This script is installed (copied) to /etc/init.d/tegu and then the command 23 | # 'insserv /etc/init.d/tegu' is run to add it to the list of things that are 24 | # automatically started when system enters run level 2 through 5. The script 25 | # starts BOTH tegu and the agent (5 instances). This script assumes that both 26 | # tegu and agent binaries are in the PATH. 27 | # 28 | # Usage: service tegu {start|stop|standby} 29 | # 30 | # CAUTION: this script assumes that the user ID created for tegu is 'tegu'. 31 | # If a different uer id was used the value must be changed just below 32 | # this header box. Regardless of the user ID created for tegu, the 33 | # directory in /etc is assumed to be tegu (all tegu scripts make that 34 | # assumption!) 35 | # 36 | # Date: 20 May 2014 37 | # Author: E. Scott Daniels 38 | # 39 | # Mods: 27 Aug 2014 - Now passes the second command line parameter to tegu_start 40 | # 01 Dec 2014 - Added restart command; ensure environment is set for failover 41 | # support when running 'service tegu standby'. 42 | # 14 Dec 2014 - Renamed restart to reload since service buggers restart. 43 | # 18 Dec 2014 - Ignore signal 15 to prevent kill from killing us. 44 | # 30 Jan 2015 - Added start of ha daemon. 45 | # 02 Feb 2015 - Changed start to start only the ha daemon which will start tegu 46 | # if needed on this host. Added forceup option to allow tegu to be forced 47 | # to start without the ha daemon. 48 | # 20 Feb 2015 - Added -u option to killall to supress warnings from killall 49 | # 10 Mar 2015 - Corrected missing tegu_user on the ha start in standby. 50 | # 09 Apr 2015 - Corrected typo in forcedown logic. 51 | #---------------------------------------------------------------------------------------- 52 | trap "" 15 # prevent killall from killing the script when run from service 53 | 54 | tegu_user=tegu #### change this if a different user name was setup for tegu 55 | tegu_group=tegu #### change this if a different group name was setup for tegu 56 | 57 | ### BEGIN INIT INFO 58 | # Provides: tegu 59 | # Required-Start: 60 | # Required-Stop: 0 1 6 61 | # Default-Start: 2 3 4 5 62 | # Default-Stop: 0 1 6 63 | # Short-Description: Tegu bandwidth reservation manager 64 | ### END INIT INFO 65 | 66 | set -e 67 | 68 | # /etc/init.d/tegu: start and stop Tegu bandwidth reservation maanger 69 | 70 | test -x /usr/bin/tegu || exit 0 71 | test -x /usr/bin/start_tegu || exit 0 72 | test -x /usr/bin/start_tegu_agent || exit 0 73 | test -x /usr/bin/tegu_agent || exit 0 74 | 75 | if test ! -d /var/log/tegu 76 | then 77 | mkdir /var/log/tegu 78 | fi 79 | chown $tegu_user:$tegu_group /var/log/tegu # always ensure that the ownership is correct 80 | 81 | if test ! -d /var/lib/tegu 82 | then 83 | mkdir /var/lib/tegu 84 | fi 85 | chown $tegu_user:$tegu_group /var/lib/tegu 86 | 87 | if test -d /etc/tegu 88 | then 89 | chown $tegu_user:$tegu_group /etc/tegu 90 | chown $tegu_user:$tegu_group /etc/tegu/* 91 | chmod 755 /etc/tegu 92 | chmod 600 /etc/tegu/tegu.cfg 93 | fi 94 | 95 | umask 022 96 | 97 | if ! test -f /etc/tegu/tegu.cfg 98 | then 99 | exit 0 100 | fi 101 | 102 | export PATH="${PATH:+$PATH:}/usr/bin:/usr/sbin:/sbin" # ensure key directories are there 103 | 104 | case "$1" in 105 | forceup) # forces tegu to be started; might be stopped immediately by ha daemon 106 | su -c "PATH=$PATH start_tegu" $tegu_user 107 | su -c "PATH=$PATH start_tegu_agent 1 2 3 4 5" $tegu_user 108 | ;; 109 | 110 | forcedown) # force tegu and agents down; ha might well restart them 111 | set +e 112 | su -c "killall -u $tegu_user tegu_agent" 113 | su -c "killall -u $tegu_user tegu" 114 | ;; 115 | 116 | start) 117 | su -c "PATH=$PATH start_tegu_ha" $tegu_user # start high avail daemon; let it decided if Tegu should be running here 118 | ;; 119 | 120 | stop) # stop everything, including the ha process 121 | set +e # don't exit if either fail (which they will if tegu not running) 122 | ha_pid="$(ps aux | grep "[p]ython.*tegu_ha" | awk '{ print $2 }' )" # get the pid of the ha process 123 | if test -n "$ha_pid" 124 | then 125 | su -c "kill -9 $ha_pid" tegu # python seems to ignore term signals, send it down hard 126 | fi 127 | 128 | su -c "killall -u $tegu_user tegu_agent" $tegu_user 129 | su -c "killall -u $tegu_user tegu" $tegu_user 130 | ;; 131 | 132 | standby) 133 | if test ! -f /etc/tegu/active 134 | then 135 | touch /etc/tegu/standby 136 | chown $tegu_user:$tegu_group /etc/tegu/standby 137 | su -c "PATH=$PATH start_tegu" tegu >/dev/null 2>&1 # this will fail, but we want to ensure environment (cron etc.) is setup 138 | fi 139 | su -c "PATH=$PATH start_tegu_ha" $tegu_user # start high avail daemon 140 | ;; 141 | 142 | reload) 143 | set +e 144 | su -c "killall -u $tegu_user tegu_agent" 145 | su -c "killall -u $tegu_user tegu" 146 | 147 | # tegu_ha will restart things (safe to run this even if tegu_ha is already running) 148 | su -c "PATH=$PATH start_tegu_ha" tegu # start high avail daemon; let it decided if Tegu should be running here 149 | ;; 150 | 151 | 152 | status) 153 | /usr/bin/tegu_req ping|grep -q OK # exit with non-zero if not running 154 | exit $? 155 | ;; 156 | 157 | *) 158 | echo "Usage: $0 {start|stop|restart}" 159 | exit 1 160 | esac 161 | 162 | exit 0 163 | -------------------------------------------------------------------------------- /system/tegu_standby.ksh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ksh 2 | # vi: sw=4 ts=4: 3 | # 4 | # --------------------------------------------------------------------------- 5 | # Copyright (c) 2013-2015 AT&T Intellectual Property 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at: 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # --------------------------------------------------------------------------- 19 | # 20 | 21 | # 22 | # Mnemonic: tegu_standby 23 | # Abstract: Simple script to either turn on or turn off standby mode. We do this by creating/removing 24 | # a file in the TEGU_ETCD directory (/etc/tegu by default). 25 | # The first parameter must be on, or off to affect change. The parameter state will write 26 | # the current state to the tty and exit. Any other invocation will restult in a usage 27 | # message. The command must be executed as the tegu user or it will error. When turning off 28 | # stand-by mode, an attempt will be made to restore the most recent checkpoint files from 29 | # the synchronisation archive. This can be disabled by adding a second parameter: norestore. 30 | # 31 | # Date: 25 July 2014 32 | # Author: E. Scott Daniels 33 | # 34 | # Mod: 27 Aug 2014 - Added protection against chef running 'service tegu standby' if the node 35 | # has been put into active mode. 36 | # 10 Mar 2015 - Made less chatty since it gets invoked every n seconds by tegu_ha and 37 | # thus pollutes the log. 38 | # -------------------------------------------------------------------------------------------------- 39 | 40 | 41 | function verify_id 42 | { 43 | whoiam=$( id -n -u ) 44 | if [[ $whoiam != $tegu_user ]] 45 | then 46 | echo "Only the tegu user ($tegu_user) can affect the state; ($(whoami) is not acceptable) [FAIL]" 47 | echo "'sudo su $tegu_user' and rerun this script" 48 | echo "" 49 | exit 1 50 | fi 51 | } 52 | 53 | # -------------------------------------------------------------------------------------------------- 54 | 55 | export TEGU_ROOT=${TEGU_ROOT:-/var} 56 | logd=${TEGU_LOGD:-/var/log/tegu} 57 | libd=${TEGU_LIBD:-/var/lib/tegu} 58 | etcd=${TEGU_ETCD:-/etc/tegu} 59 | tegu_user=${TEGU_USER:-tegu} 60 | 61 | standby_file=$etcd/standby # prevents tegu_start and tegu_start_agent scripts from running 62 | active_file=$etcd/active # sole purpose is to prevent damage when chef runs if node has been made active 63 | 64 | if [[ ! -d $etcd ]] 65 | then 66 | echo "tegu seems not to be installed on this host: $etcd doesn't exist" 67 | exit 1 68 | fi 69 | 70 | case $1 in 71 | off) # standby off mode -- tegu is allowed to be active on this host 72 | verify_id 73 | rm -f $standby_file 74 | touch $active_file 75 | echo "standby turned off" 76 | if [[ -z $2 || $2 != "norestore" ]] # restore last chkpt sync if we can 77 | then 78 | echo "restoring checkpoints from synchronisation [OK]" 79 | tegu_synch restore 80 | fi 81 | ;; 82 | 83 | on) # tegu not allowed to start; standby host 84 | verify_id 85 | touch $standby_file 86 | rm -f $active_file 87 | ;; 88 | 89 | state) 90 | if [[ -f $standby_file ]] 91 | then 92 | echo "this host is a tegu standby host" 93 | else 94 | echo "this host is an active tegu host" 95 | fi 96 | ;; 97 | 98 | -\?) echo "usage: $0 {off [norestore]|on|state}" ;; 99 | 100 | *) echo "usage: $0 {off [norestore]|on|state}"; exit 1 ;; 101 | esac 102 | 103 | exit 0 104 | -------------------------------------------------------------------------------- /system/tegu_synch.ksh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ksh 2 | # vi: sw=4 ts=4: 3 | # 4 | # --------------------------------------------------------------------------- 5 | # Copyright (c) 2013-2015 AT&T Intellectual Property 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at: 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # --------------------------------------------------------------------------- 19 | # 20 | 21 | # 22 | # Mnemonic: tegu_synch 23 | # Abstract: Simple script to take a snapshot of the checkpoint environment and push it off to 24 | # the stand-by hosts. Stand-by hosts are expected to be listed one per line in 25 | # If the first parameter on the command line is "recover" then this script will 26 | # attempt to restore the most receent synch file into the chkpt directory. 27 | # 28 | # CAUTION: A _huge_ assumption is made here -- the TEGU_ROOT directory on each 29 | # host is the same! 30 | # 31 | # Exit: an exit code of 1 is an error while an exit code of 2 is a warning and the calling 32 | # script might be able to ignore it depending on what action was attempted. An exit 33 | # code of zero is good. 34 | # 35 | # Date: 25 July 2014 36 | # Author: E. Scott Daniels 37 | # 38 | # Mod: 14 Jan - added provision to reload that will search for an old style name (no host) 39 | # if one with a host cannot be found. 40 | # 02 Jul 2015 - correct bug that allowed an old gzip file to be used when newer 41 | # checkpoint files exist. 42 | # -------------------------------------------------------------------------------------------------- 43 | 44 | trap "rm -f /tmp/PID$$.*" 1 2 3 15 EXIT 45 | 46 | function verify_id 47 | { 48 | whoiam=$( id -n -u ) 49 | if [[ $whoiam != $tegu_user ]] 50 | then 51 | echo "Only the tegu user ($tegu_user) can affect the state; ($(whoami) is not acceptable) [FAIL]" 52 | echo "'sudo su $tegu_user' and rerun this script" 53 | echo "" 54 | exit 1 55 | fi 56 | } 57 | 58 | # check for standby mode and bail if this is a standby node 59 | function ensure_active 60 | { 61 | 62 | if [[ -f $standby_file ]] 63 | then 64 | echo "WRN: this host is a tegu standby host and does not synch its files" 65 | exit 0 66 | fi 67 | } 68 | 69 | # capture a config file 70 | function cap_config 71 | { 72 | if [[ -f $etcd/$1 ]] 73 | then 74 | if ! cp $etcd/$1 chkpt/ 75 | then 76 | echo "WRN: unable to capture a copy of the config file ($etcd/$1) with the check point files" >&2 77 | fi 78 | else 79 | echo "WRN: $etcd/$1 does not exist, config was captured with the checkpoint files" >&2 80 | fi 81 | } 82 | 83 | # restore a configuration file 84 | function restore_config 85 | { 86 | if [[ -f $1 ]] # if a config file was captured with the checkpoint files 87 | then 88 | if cp $1 $etcd/ 89 | then 90 | echo "config file ($1) restored and copied into $etcd [OK]" >&2 91 | else 92 | echo "WRN: unable to copy config file ($1) into $etcd" >&2 93 | fi 94 | fi 95 | } 96 | 97 | # -------------------------------------------------------------------------------------------------- 98 | 99 | export TEGU_ROOT=${TEGU_ROOT:-/var} 100 | logd=${TEGU_LOGD:-/var/log/tegu} 101 | libd=${TEGU_LIBD:-/var/lib/tegu} 102 | etcd=${TEGU_ETCD:-/etc/tegu} 103 | chkptd=$TEGU_LIBD/chkpt 104 | tegu_user=${TEGU_USER:-tegu} 105 | 106 | ssh_opts="-o StrictHostKeyChecking=no -o PreferredAuthentications=publickey" 107 | 108 | standby_file=$etcd/standby 109 | restore=0 110 | 111 | case $1 in 112 | restore) #restore the latest sync into the chkpt directory 113 | restore=1 114 | ;; 115 | 116 | *) ensure_active;; 117 | esac 118 | 119 | if [[ ! -d $etcd ]] 120 | then 121 | echo "WRN: tegu seems not to be installed on this host: $etcd doesn't exist" >&2 122 | exit 1 123 | fi 124 | 125 | verify_id # ensure we're running with tegu user id 126 | 127 | if ! cd $libd 128 | then 129 | echo "CRI: unable to switch to tegu lib directory: $libd [FAIL]" >&2 130 | exit 1 131 | fi 132 | 133 | if [[ ! -d chkpt ]] 134 | then 135 | if (( restore )) 136 | then 137 | if ! mkdir chkpt 138 | then 139 | echo "CRI: unable to create the checkpoint directory $PWD/chkpt" >&2 140 | exit 1 141 | fi 142 | else 143 | echo "WRN: no checkpoint directory exists on this host, nothing done" >&2 144 | exit 2 145 | fi 146 | fi 147 | 148 | 149 | if (( ! restore )) # take a snap shot of our current set of chkpt files and the current config from $etcd 150 | then 151 | if [[ ! -f $etcd/standby_list ]] 152 | then 153 | echo "WRN: no stand-by list ($etcd/standby_list), nothing done" >&2 154 | exit 2 155 | fi 156 | 157 | # chef gets pissy if we restore things into etc, so we don't any more. 158 | #cap_config tegu.cfg # we need to snarf several of the current config files too 159 | #ls $etcd/*.json | while read jfile 160 | #do 161 | # cap_config ${jfile##*/} 162 | #done 163 | 164 | m=$( date +%M ) # current minutes 165 | n=$(( (m/5) * 5 )) # round current minutes to previous 5 min boundary 166 | host=$( hostname ) 167 | tfile=/tmp/PID$$.chkpt.tgz # local tar file 168 | rfile=$libd/chkpt_synch.$host.$n.tgz # remote archive (we should save just 12 so no need for cleanup) 169 | tar -cf - chkpt |gzip >$tfile 170 | 171 | while read host 172 | do 173 | if ! scp $ssh_opts -o PasswordAuthentication=no $tfile $tegu_user@$host:$rfile 174 | then 175 | echo "CRI: unable to copy the synch file to remote host $host" >&2 176 | else 177 | echo "successful copy of sync file to $host [OK]" 178 | fi 179 | done <$etcd/standby_list 180 | else 181 | ls -t $libd/chkpt_synch.*.*.tgz | head -1 |read synch_file 182 | if [[ -z $synch_file ]] 183 | then 184 | ls -t $libd/chkpt_synch.*.tgz | head -1 | read synch_file # old style (no host name) 185 | if [[ -z $synch_file ]] 186 | then 187 | echo "WRN: cannot find a synch file, no restore of synchronised data" >&2 188 | exit 2 189 | fi 190 | fi 191 | 192 | bfile=$libd/synch_backup.tgz # we'll take a snapshot of what was there just to prevent some accidents 193 | tar -cf - chkpt | gzip >$bfile 194 | 195 | newer_list=$( find $chkptd -name "resmgr_*" -newer $synch_file ) 196 | if [[ -n $newer_list ]] 197 | then 198 | echo "WRN: did not restore from tar, $synch_file is older than some checkpoint files" 199 | else 200 | gzip -dc $synch_file | tar -xf - # unload the synch file into the directory 201 | echo "synch file ($synch_file) was restored into $PWD/chkpt [OK]" 202 | 203 | # chef gets pissy if we do this, so we don't any more. 204 | #restore_config chkpt/tegu.cfg # restore the config files 205 | #ls chkpt/*.json | while read jfile 206 | #do 207 | # restore_config $jfile 208 | #done 209 | fi 210 | fi 211 | 212 | exit 0 213 | --------------------------------------------------------------------------------