├── agent
├── README
├── bandwidth
│ ├── ql_set_trunks.ksh
│ ├── ql_filter_rtr.ksh
│ ├── map_mac2phost.ksh
│ ├── ql_bwow_fmods.ksh
│ ├── ql_suss_queues.ksh
│ ├── purge_ovs_queues.ksh
│ ├── ql_pass_fmods.ksh
│ └── ql_setup_irl.ksh
└── mirror
│ └── tegu_del_mirror.ksh
├── system
├── crontab.qlite
├── start_tegu_ha.ksh
├── start_tegu_agent.ksh
├── tegu_standby.ksh
├── tegu_rc.ksh
├── tegu_synch.ksh
└── ql_snuff.ksh
├── LICENSE
├── managers
├── xmanagers_test.go
├── fq_pass.go
├── mgr_tools.go
├── http_fetch.go
├── res_mgr_pt.go
├── net_req.go
└── res_mgr_mirror.go
├── const.go
├── gizmos
├── spq.go
├── gizmos_lite_test.go
├── init.go
├── mbox.go
├── lite.go
├── flowmod.go
├── gizmos_pt_test.go
├── gizmos_tools_test.go
├── gizmos_test.go
├── gizmos_net_test.go
├── mlag.go
├── pledge.go
├── queue.go
├── fence.go
├── pledge_base.go
├── pledge_test.go
├── host.go
└── pledge_window.go
├── doc
└── rjprt.1
├── README
├── README.md
└── main
└── rjprt.go
/agent/README:
--------------------------------------------------------------------------------
1 | This directory contains interface scripts which the tegu-agent
2 | uses to execute direct interaction with switches.
3 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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_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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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_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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------