@@ -63,13 +63,25 @@ func goSRExit() error {
63
63
return nil
64
64
}
65
65
66
- func createGTPUEntity (ipAddress string ) (* gtpv1.UPlaneConn , error ) {
67
- // add SID as ip address (padded with zeros) to iface LinuxSRLinkName
68
- if ! strings .HasSuffix (ipAddress , "/128" ) {
69
- return nil , fmt .Errorf ("IP Address for GTP Entity must be an IPv6 address with a /128 mask" )
70
- }
71
- if err := runIP ("address" , "replace" , ipAddress , "dev" , LinuxSRLinkName ); err != nil {
72
- return nil , err
66
+ func createGTPUEntity (ipAddress string , ipversion int ) (* gtpv1.UPlaneConn , error ) {
67
+ // TODO: replace the GTP entity with a creation of GTP packet by gopacket (don't forget response to GTP Echo (option))
68
+ switch ipversion {
69
+ case 4 :
70
+ if ! strings .HasSuffix (ipAddress , "/32" ) {
71
+ return nil , fmt .Errorf ("IP Address for this GTP Entity must be an IPv4 address with a /32 mask" )
72
+ }
73
+ // we don't add ip address in ipv4 case because the address is expected to already exist
74
+ case 6 :
75
+ if ! strings .HasSuffix (ipAddress , "/128" ) {
76
+ return nil , fmt .Errorf ("IP Address for this GTP Entity must be an IPv6 address with a /128 mask" )
77
+ }
78
+ // add ip address (padded with zeros) to iface LinuxSRLinkName
79
+ // (we expect to have no address set in the ip range of the SID)
80
+ if err := runIP ("address" , "replace" , ipAddress , "dev" , LinuxSRLinkName ); err != nil {
81
+ return nil , err
82
+ }
83
+ default :
84
+ return nil , fmt .Errorf ("IP version should be 4 or 6" )
73
85
}
74
86
75
87
ipAddressNoMask := strings .SplitN (ipAddress , "/" , 2 )[0 ]
@@ -193,18 +205,24 @@ func createEndpoints(iface *water.Interface) error {
193
205
gtpNodes = make (map [string ](* gtpv1.UPlaneConn ))
194
206
for _ , e := range SRv6 .Endpoints {
195
207
switch e .Behavior {
196
- case "End.M.GTP6.D" : // we receive GTP packet and send SRv6 packets
208
+ case "End.MAP" :
209
+ return fmt .Errorf ("Not implemented" )
210
+ case "End.M.GTP6.D" : // we receive GTP packet and send SRv6 packets with ArgsMobSession stored in arguments of SRH[0]
211
+ return fmt .Errorf ("Not implemented" )
212
+ case "End.M.GTP6.D.Di" : // we receive GTP packet and send SRv6 packets, no ArgsMobSession is stored
197
213
if e .Options == nil || e .Options .SourceAddress == nil {
198
214
return fmt .Errorf ("Options field must contain a set-source-address parameter" )
215
+ // TODO: after replacement of GTPU-Entity creation by gopacket, this parameter should become optional (default: dst addr of the received packet)
199
216
}
200
217
if ! strings .HasSuffix (e .Sid , "/128" ) {
201
- return fmt .Errorf ("SID of End.M.GTP6.D must be a /128" )
218
+ return fmt .Errorf ("SID of End.M.GTP6.Di must be a /128" )
202
219
}
220
+ // FIXME: canonize gtpentityAddr
203
221
gtpentityAddr := e .Sid // we receive GTP packets having this destination address
204
222
srAddr := net .ParseIP (strings .SplitN (* e .Options .SourceAddress , "/" , 2 )[0 ]) // we send SR packets using this source address
205
223
// add a GTP Node to be able to receive GTP packets
206
224
if gtpNodes [gtpentityAddr ] == nil {
207
- entity , err := createGTPUEntity (gtpentityAddr )
225
+ entity , err := createGTPUEntity (gtpentityAddr , 6 )
208
226
if err != nil {
209
227
return err
210
228
}
@@ -220,8 +238,9 @@ func createEndpoints(iface *water.Interface) error {
220
238
gtpNodes [gtpentityAddr ].AddHandler (message .MsgTypeTPDU , func (c gtpv1.Conn , senderAddr net.Addr , msg message.Message ) error {
221
239
return tpduHandler (iface , srAddr , c , senderAddr , msg , hoplimit )
222
240
})
223
- case "End.M.GTP6.E" : // we receive SRv6 packets and send GTP packets
241
+ case "End.M.GTP6.E" : // we receive SRv6 packets and send GTP6 packets
224
242
if e .Options == nil || e .Options .SourceAddress == nil {
243
+ // TODO: after replacement of GTPU-Entity creation by gopacket, this parameter should become optional (default: dst addr of the received packet)
225
244
return fmt .Errorf ("Options field must contain a set-source-address parameter" )
226
245
}
227
246
if ! strings .HasSuffix (* e .Options .SourceAddress , "/128" ) {
@@ -236,25 +255,102 @@ func createEndpoints(iface *water.Interface) error {
236
255
if err != nil {
237
256
return err
238
257
}
239
- if netSize > (128 - 8 - 8 * 4 ) {
258
+ if netSize > maxNetSize {
259
+ return fmt .Errorf ("Maximum network size for SID is /%d" , maxNetSize )
260
+ }
261
+ if netSize % 8 != 0 {
262
+ return fmt .Errorf ("Network size for SID must be multiple of 8" ) // FIXME: handle bit shifts
263
+ }
264
+ // FIXME: canonize srAddr
265
+ srAddr := e .Sid // we receive SR packets having this destination address
266
+ gtpentityAddr := * e .Options .SourceAddress // we send GTP packets using this source address
267
+ // add a GTP Node to be able to respond to GTP Echo Requests
268
+ if gtpNodes [gtpentityAddr ] == nil {
269
+ entity , err := createGTPUEntity (gtpentityAddr , 6 )
270
+ if err != nil {
271
+ return err
272
+ }
273
+ gtpNodes [gtpentityAddr ] = entity
274
+ }
275
+ // create SRToGTPNode
276
+ n , err := NewSRToGTPNode (srAddr , gtpentityAddr , 6 )
277
+ if err != nil {
278
+ return err
279
+ } else {
280
+ srNodes [srAddr ] = n
281
+ }
282
+ case "End.M.GTP4.E" : // we receive SRv6 packets and send GTP4 packets
283
+ if e .Options == nil || e .Options .SourceAddress == nil {
284
+ // TODO: after replacement of GTPU-Entity creation by gopacket, check the IPv4 source address from IPv6 dest addr argument space
285
+ return fmt .Errorf ("Options field must contain a set-source-address parameter" )
286
+ }
287
+ if ! strings .HasSuffix (* e .Options .SourceAddress , "/32" ) {
288
+ return fmt .Errorf ("set-source-address parameter of End.M.GTP4.E must be explicitly a /32 address" )
289
+ }
290
+ if err := runIP ("-6" , "route" , "add" , e .Sid , "dev" , NextmnSRTunName , "table" , RTTableName , "proto" , RTProtoName ); err != nil {
291
+ return err
292
+ }
293
+ maxNetSize := 128 - (32 + 8 + 8 * 4 ) // [ SID + IPv4 DA + QFI + R + U + TEID ]
294
+ netSize , err := strconv .Atoi (strings .SplitN (e .Sid , "/" , 2 )[1 ])
295
+
296
+ if err != nil {
297
+ return err
298
+ }
299
+ if netSize > maxNetSize {
240
300
return fmt .Errorf ("Maximum network size for SID is /%d" , maxNetSize )
241
301
}
242
302
if netSize % 8 != 0 {
243
- return fmt .Errorf ("Network size for SID must be multiple of 8" ) // FIXME
303
+ return fmt .Errorf ("Network size for SID must be multiple of 8" ) // FIXME: handle bit shifts
244
304
}
245
305
srAddr := e .Sid // we receive SR packets having this destination address
246
306
gtpentityAddr := * e .Options .SourceAddress // we send GTP packets using this source address
247
307
// add a GTP Node to be able to respond to GTP Echo Requests
248
308
if gtpNodes [gtpentityAddr ] == nil {
249
- entity , err := createGTPUEntity (gtpentityAddr )
309
+ entity , err := createGTPUEntity (gtpentityAddr , 4 )
250
310
if err != nil {
251
311
return err
252
312
}
253
313
gtpNodes [gtpentityAddr ] = entity
254
314
}
255
315
// create SRToGTPNode
256
- srNodes [srAddr ] = NewSRToGTPNode (srAddr , gtpentityAddr )
316
+ n , err := NewSRToGTPNode (srAddr , gtpentityAddr , 4 )
317
+ if err != nil {
318
+ return err
319
+ } else {
320
+ srNodes [srAddr ] = n
321
+ }
322
+ case "H.M.GTP4.D" :
323
+ if e .Options == nil || e .Options .SourceAddress == nil {
324
+ // TODO: this parameter should be optional (default: sid + dst addr of the received packet)
325
+ return fmt .Errorf ("Options field must contain a set-source-address parameter" )
326
+ }
327
+ if ! strings .HasSuffix (e .Sid , "/32" ) {
328
+ return fmt .Errorf ("SID of H.GTP4.d must be a /32" )
329
+ }
330
+ gtpentityAddr := e .Sid // we receive GTP packets having this destination address
331
+ srAddr := net .ParseIP (strings .SplitN (* e .Options .SourceAddress , "/" , 2 )[0 ]) // we send SR packets using this source address
332
+ // add a GTP Node to be able to receive GTP packets
333
+ if gtpNodes [gtpentityAddr ] == nil {
334
+ entity , err := createGTPUEntity (gtpentityAddr , 4 )
335
+ if err != nil {
336
+ return err
337
+ }
338
+ gtpNodes [gtpentityAddr ] = entity
339
+ }
340
+ // hop limit is set at start of the server, to avoid reading it at each packet reception
341
+ hoplimit , err := getipv6hoplimit (NextmnSRTunName )
342
+ if err != nil {
343
+ return err
344
+ }
345
+
346
+ // add handler that will allow GTP decap & SR encap
347
+ gtpNodes [gtpentityAddr ].AddHandler (message .MsgTypeTPDU , func (c gtpv1.Conn , senderAddr net.Addr , msg message.Message ) error {
348
+ return tpduHandler (iface , srAddr , c , senderAddr , msg , hoplimit )
349
+ })
350
+ case "End.Limit" :
351
+ return fmt .Errorf ("Not implemented" )
257
352
default :
353
+ // pass: other Behaviors can be implemented on linux side (see linux-sr.go)
258
354
}
259
355
}
260
356
return nil
0 commit comments