Skip to content

Commit bdd0a6b

Browse files
committed
Source GTP4 for downlink
1 parent ce2077c commit bdd0a6b

6 files changed

Lines changed: 83 additions & 20 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ require (
1010
github.com/lib/pq v1.10.9
1111
github.com/nextmn/gopacket-gtp v0.0.8
1212
github.com/nextmn/gopacket-srv6 v0.0.8
13-
github.com/nextmn/json-api v0.0.16
13+
github.com/nextmn/json-api v0.0.17-0.20250117120523-f0c7cb4f9792
1414
github.com/nextmn/logrus-formatter v0.0.1
1515
github.com/nextmn/rfc9433 v0.0.2
1616
github.com/sirupsen/logrus v1.9.3

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ github.com/nextmn/gopacket-srv6 v0.0.8 h1:oP4wuJ7dOiV/gWmX3zoFcdp2dKdSWLUaxH2fJ3
5959
github.com/nextmn/gopacket-srv6 v0.0.8/go.mod h1:2Tyuo9zsG0bP2IhC4tVRgPRuyUqOgrvEEH9seJSZTlU=
6060
github.com/nextmn/json-api v0.0.16 h1:RU5eTVvnwrYK0Zmh/EhdO7Q3A+hUWjavg9ytJknaYTU=
6161
github.com/nextmn/json-api v0.0.16/go.mod h1:CQXeNPj9MDGsEExtnqJFIGjLgZAKsmOoO2fy+mep7Ak=
62+
github.com/nextmn/json-api v0.0.17-0.20250117102021-8f2d7604eabc h1:WZg8N41u0VIeII/AS5U7aVjPCuGP+c3PdAd782xGxtI=
63+
github.com/nextmn/json-api v0.0.17-0.20250117102021-8f2d7604eabc/go.mod h1:CQXeNPj9MDGsEExtnqJFIGjLgZAKsmOoO2fy+mep7Ak=
64+
github.com/nextmn/json-api v0.0.17-0.20250117120523-f0c7cb4f9792 h1:eeigbuE6dbRFWl76iOvP+FgvLtkfgL7d0dRnGDgCJ5w=
65+
github.com/nextmn/json-api v0.0.17-0.20250117120523-f0c7cb4f9792/go.mod h1:CQXeNPj9MDGsEExtnqJFIGjLgZAKsmOoO2fy+mep7Ak=
6266
github.com/nextmn/logrus-formatter v0.0.1 h1:Bsf78jjiEESc+rV8xE6IyKj4frDPGMwXFNrLQzm6A1E=
6367
github.com/nextmn/logrus-formatter v0.0.1/go.mod h1:vdSZ+sIcSna8vjbXkSFxsnsKHqRwaUEed4JCPcXoGyM=
6468
github.com/nextmn/rfc9433 v0.0.2 h1:6FjMY+Qy8MNXQ0PPxezUsyXDxJiCbTp5j3OcXQgIQh8=

internal/database/database.go

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,14 @@ func (db *Database) InsertRule(ctx context.Context, r n4tosrv6.Rule) (*uuid.UUID
125125
} else {
126126
dst = r.Match.Payload.Dst.String() + "/32"
127127
}
128-
err := stmt.QueryRowContext(ctx, r.Enabled, dst, pq.Array(srh)).Scan(&id)
128+
src_ipv6 := "::"
129+
if r.Action.SourceGtp4 != nil {
130+
src_ipv6 = r.Action.SourceGtp4.String()
131+
} else {
132+
return nil, fmt.Errorf("Empty SourceGtp4 for downlink Action")
133+
}
134+
135+
err := stmt.QueryRowContext(ctx, r.Enabled, dst, pq.Array(srh), src_ipv6).Scan(&id)
129136
return &id, err
130137
} else {
131138
return nil, fmt.Errorf("Procedure not registered")
@@ -139,13 +146,14 @@ func (db *Database) GetRule(ctx context.Context, uuid uuid.UUID) (n4tosrv6.Rule,
139146
var type_uplink bool
140147
var enabled bool
141148
var action_srh []string
149+
var action_source_gtp4 *string
142150
var match_ue_ip string
143151
var match_gnb_ip []string
144152
var match_service_ip *string
145153
var match_uplink_teid *uint32
146154
var match_uplink_upf *string
147155
if stmt, ok := db.stmt["get_rule"]; ok {
148-
err := stmt.QueryRowContext(ctx, uuid.String()).Scan(&type_uplink, &enabled, pq.Array(&action_srh), &match_ue_ip, pq.Array(&match_gnb_ip), &match_uplink_teid, &match_uplink_upf, &match_service_ip)
156+
err := stmt.QueryRowContext(ctx, uuid.String()).Scan(&type_uplink, &enabled, pq.Array(&action_srh), &action_source_gtp4, &match_ue_ip, pq.Array(&match_gnb_ip), &match_uplink_teid, &match_uplink_upf, &match_service_ip)
149157
if err != nil {
150158
return n4tosrv6.Rule{}, err
151159
}
@@ -202,8 +210,18 @@ func (db *Database) GetRule(ctx context.Context, uuid uuid.UUID) (n4tosrv6.Rule,
202210
return n4tosrv6.Rule{}, err
203211
}
204212

213+
if action_source_gtp4 == nil {
214+
return n4tosrv6.Rule{}, fmt.Errorf("Empty SourceGtp4 for downlink rule")
215+
}
216+
217+
source_gtp4, err := netip.ParseAddr(*action_source_gtp4)
218+
if err != nil {
219+
return n4tosrv6.Rule{}, err
220+
}
221+
205222
rule.Action = n4tosrv6.Action{
206-
SRH: *srh,
223+
SRH: *srh,
224+
SourceGtp4: &source_gtp4,
207225
}
208226

209227
return rule, err
@@ -217,6 +235,7 @@ func (db *Database) GetRules(ctx context.Context) (n4tosrv6.RuleMap, error) {
217235
var type_uplink bool
218236
var enabled bool
219237
var action_srh []string
238+
var action_source_gtp4 *string
220239
var match_ue_ip string
221240
var match_gnb_ip []string
222241
var match_uplink_teid *uint32
@@ -234,7 +253,7 @@ func (db *Database) GetRules(ctx context.Context) (n4tosrv6.RuleMap, error) {
234253
// avoid looping if no longer necessary
235254
return n4tosrv6.RuleMap{}, ctx.Err()
236255
default:
237-
err := rows.Scan(&uuid, &type_uplink, &enabled, pq.Array(&action_srh), &match_ue_ip, pq.Array(&match_gnb_ip), &match_uplink_teid, &match_uplink_upf, &match_service_ip)
256+
err := rows.Scan(&uuid, &type_uplink, &enabled, pq.Array(&action_srh), &action_source_gtp4, &match_ue_ip, pq.Array(&match_gnb_ip), &match_uplink_teid, &match_uplink_upf, &match_service_ip)
238257
if err != nil {
239258
return m, err
240259
}
@@ -285,14 +304,23 @@ func (db *Database) GetRules(ctx context.Context) (n4tosrv6.RuleMap, error) {
285304
}
286305
}
287306
}
307+
if action_source_gtp4 == nil {
308+
return n4tosrv6.RuleMap{}, fmt.Errorf("Empty SourceGtp4 for downlink rule")
309+
}
310+
311+
source_gtp4, err := netip.ParseAddr(*action_source_gtp4)
312+
if err != nil {
313+
return n4tosrv6.RuleMap{}, err
314+
}
288315

289316
srh, err := n4tosrv6.NewSRH(action_srh)
290317
if err != nil {
291318
return n4tosrv6.RuleMap{}, err
292319
}
293320

294321
rule.Action = n4tosrv6.Action{
295-
SRH: *srh,
322+
SRH: *srh,
323+
SourceGtp4: &source_gtp4,
296324
}
297325
m[uuid] = rule
298326
}
@@ -351,36 +379,55 @@ func (db *Database) GetUplinkAction(ctx context.Context, uplinkFTeid jsonapi.Fte
351379
if err != nil {
352380
return n4tosrv6.Action{}, err
353381
}
354-
return n4tosrv6.Action{SRH: *srh}, err
382+
return n4tosrv6.Action{
383+
SRH: *srh,
384+
}, err
355385
} else {
356386
return n4tosrv6.Action{}, fmt.Errorf("Procedure not registered")
357387
}
358388
}
359389

360390
func (db *Database) GetDownlinkAction(ctx context.Context, ueIp netip.Addr) (n4tosrv6.Action, error) {
361391
var action_srh []string
392+
var action_source_gtp4 *string
362393
if stmt, ok := db.stmt["get_downlink_action"]; ok {
363-
err := stmt.QueryRowContext(ctx, ueIp.String()).Scan(pq.Array(&action_srh))
394+
err := stmt.QueryRowContext(ctx, ueIp.String()).Scan(pq.Array(&action_srh), &action_source_gtp4)
364395
if err != nil {
365396
return n4tosrv6.Action{}, err
366397
}
367398
srh, err := n4tosrv6.NewSRH(action_srh)
368399
if err != nil {
369400
return n4tosrv6.Action{}, err
370401
}
371-
return n4tosrv6.Action{SRH: *srh}, err
402+
if action_source_gtp4 == nil {
403+
return n4tosrv6.Action{}, fmt.Errorf("Empty SourceGtp4 for downlink rule")
404+
}
405+
source_gtp4, err := netip.ParseAddr(*action_source_gtp4)
406+
if err != nil {
407+
return n4tosrv6.Action{}, err
408+
}
409+
return n4tosrv6.Action{
410+
SRH: *srh,
411+
SourceGtp4: &source_gtp4,
412+
}, err
372413
} else {
373414
return n4tosrv6.Action{}, fmt.Errorf("Procedure not registered")
374415
}
375416
}
376417

377418
func (db *Database) UpdateAction(ctx context.Context, uuidRule uuid.UUID, action n4tosrv6.Action) error {
378419
srh := []string{}
420+
source_gtp4 := "::"
421+
if action.SourceGtp4 != nil {
422+
source_gtp4 = action.SourceGtp4.String()
423+
} else {
424+
return fmt.Errorf("Empty SourceGtp4 for downlink rule")
425+
}
379426
for _, ip := range action.SRH {
380427
srh = append(srh, ip.String())
381428
}
382429
if stmt, ok := db.stmt["update_action"]; ok {
383-
_, err := stmt.ExecContext(ctx, uuidRule.String(), pq.Array(srh))
430+
_, err := stmt.ExecContext(ctx, uuidRule.String(), pq.Array(srh), source_gtp4)
384431
return err
385432
} else {
386433
return fmt.Errorf("Procedure not registered")

internal/database/database.sql

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ CREATE TABLE IF NOT EXISTS rule (
88
type_uplink BOOL NOT NULL,
99
enabled BOOL NOT NULL,
1010
action_srh INET ARRAY NOT NULL,
11+
action_source_gtp4 INET,
1112
match_ue_ip CIDR NOT NULL,
1213
match_gnb_ip CIDR ARRAY,
1314
match_service_ip CIDR,
@@ -33,12 +34,13 @@ END;$$;
3334
CREATE OR REPLACE PROCEDURE insert_downlink_rule(
3435
IN in_enabled BOOL, IN in_ue_ip CIDR,
3536
IN in_srh INET ARRAY,
37+
IN in_source_gtp4 INET,
3638
OUT out_uuid UUID
3739
)
3840
LANGUAGE plpgsql AS $$
3941
BEGIN
40-
INSERT INTO rule(type_uplink, enabled, match_ue_ip, action_srh)
41-
VALUES(FALSE, in_enabled, in_ue_ip, in_srh) RETURNING rule.uuid INTO out_uuid;
42+
INSERT INTO rule(type_uplink, enabled, match_ue_ip, action_srh, action_source_gtp4)
43+
VALUES(FALSE, in_enabled, in_ue_ip, in_srh, in_source_gtp4) RETURNING rule.uuid INTO out_uuid;
4244
END;$$;
4345

4446

@@ -78,11 +80,13 @@ END;$$;
7880

7981
CREATE OR REPLACE PROCEDURE update_action(
8082
IN in_uuid UUID,
81-
IN in_srh INET ARRAY
83+
IN in_srh INET ARRAY,
84+
IN in_source_gtp4 INET
8285
)
8386
LANGUAGE plpgsql AS $$
8487
BEGIN
8588
UPDATE rule SET action_srh = in_srh WHERE rule.uuid = in_uuid;
89+
UPDATE rule SET action_source_gtp4 = in_source_gtp4 WHERE rule.uuid = in_uuid;
8690
END;$$;
8791

8892
CREATE OR REPLACE FUNCTION get_uplink_action(
@@ -111,11 +115,12 @@ CREATE OR REPLACE FUNCTION get_downlink_action(
111115
IN in_ue_ip_address INET
112116
)
113117
RETURNS TABLE (
114-
t_action_srh INET ARRAY
118+
t_action_srh INET ARRAY,
119+
t_action_source_gtp4 INET
115120
)
116121
AS $$
117122
BEGIN
118-
RETURN QUERY SELECT rule.action_srh AS "t_action_srh"
123+
RETURN QUERY SELECT rule.action_srh AS "t_action_srh", rule.action_source_gtp4 AS "t_action_source_gtp4"
119124
FROM rule
120125
WHERE (rule.type_uplink = FALSE AND rule.enabled = TRUE
121126
AND match_ue_ip && in_ue_ip_address);
@@ -128,6 +133,7 @@ RETURNS TABLE (
128133
t_type_uplink BOOL,
129134
t_enabled BOOL,
130135
t_action_srh INET ARRAY,
136+
t_action_source_gtp4 INET,
131137
t_match_ue_ip CIDR,
132138
t_match_gnb_ip CIDR ARRAY,
133139
t_match_uplink_teid BIGINT,
@@ -137,7 +143,8 @@ RETURNS TABLE (
137143
AS $$
138144
BEGIN
139145
RETURN QUERY SELECT type_uplink AS "t_type_uplink", enabled AS "t_enabled",
140-
action_srh AS "t_action_srh", match_ue_ip AS "t_match_ue_ip", match_gnb_ip AS "t_match_gnb_ip",
146+
action_srh AS "t_action_srh", action_source_gtp4 AS "t_action_source_gtp4",
147+
match_ue_ip AS "t_match_ue_ip", match_gnb_ip AS "t_match_gnb_ip",
141148
match_uplink_teid AS "t_match_uplink_teid", match_uplink_upf AS "t_match_uplink_upf",
142149
match_service_ip AS "t_match_service_ip"
143150
FROM rule
@@ -150,6 +157,7 @@ RETURNS TABLE (
150157
t_type_uplink BOOL,
151158
t_enabled BOOL,
152159
t_action_srh INET ARRAY,
160+
t_action_source_gtp4 INET,
153161
t_match_ue_ip CIDR,
154162
t_match_gnb_ip CIDR ARRAY,
155163
t_match_uplink_teid BIGINT,
@@ -160,7 +168,8 @@ AS $$
160168
BEGIN
161169
RETURN QUERY SELECT uuid AS "t_uuid", type_uplink AS "t_type_uplink",
162170
enabled AS "t_enabled",
163-
action_srh AS "t_action_srh", match_ue_ip AS "t_match_ue_ip", match_gnb_ip AS "t_match_gnb_ip",
171+
action_srh AS "t_action_srh", action_source_gtp4 AS "t_action_source_gtp4",
172+
match_ue_ip AS "t_match_ue_ip", match_gnb_ip AS "t_match_gnb_ip",
164173
match_uplink_teid AS "t_match_uplink_teid", match_uplink_upf AS "t_match_uplink_upf",
165174
match_service_ip AS "t_match_service_ip"
166175
FROM rule;

internal/database/database_gen.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/netfunc/headend-encaps-ctrl.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ func (h HeadendEncapsWithCtrl) Handle(ctx context.Context, packet []byte) ([]byt
4545
if err != nil {
4646
return nil, err
4747
}
48-
srgw_gtp_ip := netip.MustParseAddr("10.3.0.1") // FIXME: dont hardcode
48+
if action.SourceGtp4 == nil {
49+
return nil, fmt.Errorf("Empty SourceGtp4 for downlink Action")
50+
}
51+
srgw_gtp_ip := *action.SourceGtp4
4952
ipv6Src := encoding.NewMGTP4IPv6Src(h.srcPrefix, srgw_gtp_ip.As4(), 2152) // FIXME:dont hardcode udp port number to 2152
5053
src, err := ipv6Src.Marshal()
5154
if err != nil {

0 commit comments

Comments
 (0)