forked from nleiva/xrgrpc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsla.go
242 lines (217 loc) · 7.05 KB
/
sla.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
package xrgrpc
import (
"fmt"
"io"
"net"
pb "github.com/al5147/xrgrpc/proto/sla"
"github.com/pkg/errors"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
// VRFOperation handles VRF registration operations
// SL_REGOP_REGISTER = 0x1 // VRF registration
// SL_REGOP_UNREGISTER = 0x2 // VRF Un-registeration
// SL_REGOP_EOF = 0x3 // After Registration, the client is expected to send an EOF
func VRFOperation(conn *grpc.ClientConn, o int, d uint32) error {
// These are two hard-coded variables. TODO; take them as input
v := "default"
var p uint32 = 500
op := new(pb.SLRegOp)
switch o {
case 1:
*op = pb.SLRegOp_SL_REGOP_REGISTER
case 2:
*op = pb.SLRegOp_SL_REGOP_UNREGISTER
case 3:
*op = pb.SLRegOp_SL_REGOP_EOF
default:
return errors.New("Unidentified VRF Operation")
}
// 'c' is the gRPC stub.
c := pb.NewSLRoutev6OperClient(conn)
// 'a' is the object we send to the router via the stub.
a := pb.SLVrfRegMsg{
Oper: *op,
VrfRegMsgs: []*pb.SLVrfReg{
&pb.SLVrfReg{
VrfName: v,
AdminDistance: d,
VrfPurgeIntervalSeconds: p,
},
},
}
// 'r' is the result that comes back from the target.
r, err := c.SLRoutev6VrfRegOp(context.Background(), &a)
if err != nil {
return errors.Wrap(err, "gRPC SLRoutev6VrfRegOp failed")
}
// SL_SUCCESS: Entire bulk operation was successful.
// SL_SOME_ERR: Operation failed for one or more entries.
// SL_RPC_XXX: Eentire bulk operation failed.
if r.GetStatusSummary().GetStatus() != pb.SLErrorStatus_SL_SUCCESS {
// TODO: Add cases for partial errors
return fmt.Errorf("Error triggered by remote host: %s", r.GetStatusSummary().GetStatus().String())
}
return nil
}
// SetRoute ...
// SL_OBJOP_ADD = 1 // Route add. Fails if the route already exists.
// SL_OBJOP_UPDATE = 2 // Route update. Creates or updates the route.
// SL_OBJOP_DELETE = 3 // Route delete. The route path is not necessary to delete the route.
// SLRoutev6Op(ctx context.Context, in *SLRoutev6Msg, opts ...grpc.CallOption) (*SLRoutev6MsgRsp, error)
func SetRoute(conn *grpc.ClientConn, o int, ad string, d uint32, nh string) error {
// These are two hard-coded variables. TODO; take them as input
v := "default"
//intf := "HundredGigE0/0/0/1"
_, nw, err := net.ParseCIDR(ad)
if err != nil {
return errors.Errorf("Could not parse address: %s", ad)
}
mk, _ := nw.Mask.Size()
op := new(pb.SLObjectOp)
switch o {
case 1:
*op = pb.SLObjectOp_SL_OBJOP_ADD
case 2:
*op = pb.SLObjectOp_SL_OBJOP_UPDATE
case 3:
*op = pb.SLObjectOp_SL_OBJOP_DELETE
default:
return errors.New("Unidentified Object Operation")
}
// 'c' is the gRPC stub.
c := pb.NewSLRoutev6OperClient(conn)
// 'a' is the object we send to the router via the stub.
a := pb.SLRoutev6Msg{
Oper: *op,
// Correlator: x,
VrfName: v,
Routes: []*pb.SLRoutev6{
&pb.SLRoutev6{
Prefix: nw.IP,
PrefixLen: uint32(mk),
RouteCommon: &pb.SLRouteCommon{
AdminDistance: d,
},
PathList: []*pb.SLRoutePath{
&pb.SLRoutePath{
// NexthopInterface: x,
NexthopAddress: &pb.SLIpAddress{
Address: &pb.SLIpAddress_V6Address{
V6Address: net.ParseIP(nh),
},
},
},
},
},
},
}
// 'r' is the result that comes back from the target.
r, err := c.SLRoutev6Op(context.Background(), &a)
if err != nil {
return errors.Wrap(err, "gRPC SLRoutev6Op failed")
}
// SL_SUCCESS: Entire bulk operation was successful.
// SL_SOME_ERR: Operation failed for one or more entries.
// SL_RPC_XXX: Eentire bulk operation failed.
if r.GetStatusSummary().GetStatus() != pb.SLErrorStatus_SL_SUCCESS {
// TODO: Add cases for partial errors
return fmt.Errorf("Error triggered by remote host: %s, AND %v",
r.GetStatusSummary().GetStatus().String(), r.GetResults()[0].GetErrStatus().GetStatus())
}
return nil
}
// ClientInit takes care of global initialization and setup
// a notification channel
func ClientInit(conn *grpc.ClientConn) error {
ch := make(chan int)
/* Setup the notification channel */
go setupNotifChannel(conn, ch)
/* Wait for response 0: error. 1: all ok*/
if w := <-ch; w == 0 {
return errors.New("Error triggered by remote host")
}
// 'c' is the gRPC stub.
c := pb.NewSLGlobalClient(conn)
// 'a' is the object we send to the router via the stub.
a := pb.SLGlobalsGetMsg{}
// 'r' is the result that comes back from the target.
_, err := c.SLGlobalsGet(context.Background(), &a)
if err != nil {
return errors.Wrap(err, "gRPC SLGlobalsGet failed")
}
return nil
}
func setupNotifChannel(conn *grpc.ClientConn, ch chan int) {
// 'c' is the gRPC stub.
c := pb.NewSLGlobalClient(conn)
// 'a' is the object we send to the router via the stub.
// Version Major.Minor.Subversion define the API's version.
// Hardcoded to 0.0.1 for now
a := pb.SLInitMsg{
MajorVer: uint32(0),
MinorVer: uint32(0),
SubVer: uint32(1),
}
// 'st' is the streamed result that comes back from the target.
st, err := c.SLGlobalInitNotif(context.Background(), &a)
if err != nil {
ch <- 0
return
// return errors.Wrap(err, "gRPC SLGlobalInitNotif failed")
}
for {
// Loop through the responses in the stream until there is nothing left.
r, err := st.Recv()
if err == io.EOF {
return
//return nil
}
if err != nil {
return
// return errors.Wrap(err, "Recive Stream failed")
}
// Status code, interpreted based on the Event Type.
//
// case EventType == SL_GLOBAL_EVENT_TYPE_ERROR:
// case ErrStatus == SL_NOTIF_TERM:
// => Another client is attempting to take over the session.
// This session will be closed.
// case ErrStatus == (some error from SLErrorStatus)
// => Client must look into the specific error message returned.
//
// case EventType == SL_GLOBAL_EVENT_TYPE_HEARTBEAT:
// case ErrStatus == SL_SUCCESS
// => Client can safely ignore this heartbeat message.
//
// case EventType == SL_GLOBAL_EVENT_TYPE_VERSION:
// case ErrStatus == SL_SUCCESS
// => Client version accepted.
// case ErrStatus == SL_INIT_STATE_READY
// => Client version accepted.
// Any previous state was sucessfully recovered.
// case ErrStatus == SL_INIT_STATE_CLEAR
// => Client version accepted. Any previous state was lost.
// Client must replay all previous objects to server.
// case ErrStatus == SL_UNSUPPORTED_VER
// => Client and Server version mismatch. The client is not
// allowed to proceed, and the channel will be closed.
// case ErrStatus == (some error from SLErrorStatus)
// => Client must either try again, or look into the specific
// error message returned.
// Need to Fix this!!
switch r.EventType {
case pb.SLGlobalNotifType_SL_GLOBAL_EVENT_TYPE_VERSION:
ch <- 1
continue
case pb.SLGlobalNotifType_SL_GLOBAL_EVENT_TYPE_ERROR:
_ = fmt.Errorf("%s", r.ErrStatus.String())
break
case pb.SLGlobalNotifType_SL_GLOBAL_EVENT_TYPE_HEARTBEAT:
continue
default:
_ = fmt.Errorf("%s", r.ErrStatus.String())
return
}
}
}