From d0cea4d2e8a90ce2909bb99a35a24e4c36603233 Mon Sep 17 00:00:00 2001 From: Trekkie Coder Date: Tue, 19 Nov 2024 23:47:55 +0900 Subject: [PATCH] loxilb-io/loxilb#864 Initial support for lb source ranges --- api/models/loadbalance_entry.go | 94 +++++++++++++++++++++++++++++ api/restapi/embedded_spec.go | 27 +++++++++ api/restapi/handler/cluster.go | 2 +- api/restapi/handler/loadbalancer.go | 12 ++++ api/restapi/handler/prometheus.go | 6 +- api/swagger.yml | 9 +++ common/common.go | 2 + loxilb-ebpf | 2 +- pkg/loxinet/apiclient.go | 3 +- pkg/loxinet/dpebpf_linux.go | 8 ++- pkg/loxinet/rules.go | 9 +-- 11 files changed, 160 insertions(+), 14 deletions(-) diff --git a/api/models/loadbalance_entry.go b/api/models/loadbalance_entry.go index 18ae1a1b8..4932c8470 100644 --- a/api/models/loadbalance_entry.go +++ b/api/models/loadbalance_entry.go @@ -19,6 +19,9 @@ import ( // swagger:model LoadbalanceEntry type LoadbalanceEntry struct { + // values of allowed source IP + AllowedSources []*LoadbalanceEntryAllowedSourcesItems0 `json:"allowedSources"` + // values of End point servers Endpoints []*LoadbalanceEntryEndpointsItems0 `json:"endpoints"` @@ -33,6 +36,10 @@ type LoadbalanceEntry struct { func (m *LoadbalanceEntry) Validate(formats strfmt.Registry) error { var res []error + if err := m.validateAllowedSources(formats); err != nil { + res = append(res, err) + } + if err := m.validateEndpoints(formats); err != nil { res = append(res, err) } @@ -51,6 +58,32 @@ func (m *LoadbalanceEntry) Validate(formats strfmt.Registry) error { return nil } +func (m *LoadbalanceEntry) validateAllowedSources(formats strfmt.Registry) error { + if swag.IsZero(m.AllowedSources) { // not required + return nil + } + + for i := 0; i < len(m.AllowedSources); i++ { + if swag.IsZero(m.AllowedSources[i]) { // not required + continue + } + + if m.AllowedSources[i] != nil { + if err := m.AllowedSources[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("allowedSources" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("allowedSources" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + func (m *LoadbalanceEntry) validateEndpoints(formats strfmt.Registry) error { if swag.IsZero(m.Endpoints) { // not required return nil @@ -126,6 +159,10 @@ func (m *LoadbalanceEntry) validateServiceArguments(formats strfmt.Registry) err func (m *LoadbalanceEntry) ContextValidate(ctx context.Context, formats strfmt.Registry) error { var res []error + if err := m.contextValidateAllowedSources(ctx, formats); err != nil { + res = append(res, err) + } + if err := m.contextValidateEndpoints(ctx, formats); err != nil { res = append(res, err) } @@ -144,6 +181,26 @@ func (m *LoadbalanceEntry) ContextValidate(ctx context.Context, formats strfmt.R return nil } +func (m *LoadbalanceEntry) contextValidateAllowedSources(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.AllowedSources); i++ { + + if m.AllowedSources[i] != nil { + if err := m.AllowedSources[i].ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("allowedSources" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("allowedSources" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + func (m *LoadbalanceEntry) contextValidateEndpoints(ctx context.Context, formats strfmt.Registry) error { for i := 0; i < len(m.Endpoints); i++ { @@ -218,6 +275,43 @@ func (m *LoadbalanceEntry) UnmarshalBinary(b []byte) error { return nil } +// LoadbalanceEntryAllowedSourcesItems0 loadbalance entry allowed sources items0 +// +// swagger:model LoadbalanceEntryAllowedSourcesItems0 +type LoadbalanceEntryAllowedSourcesItems0 struct { + + // IP address for allowed source access + Prefix string `json:"prefix,omitempty"` +} + +// Validate validates this loadbalance entry allowed sources items0 +func (m *LoadbalanceEntryAllowedSourcesItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this loadbalance entry allowed sources items0 based on context it is used +func (m *LoadbalanceEntryAllowedSourcesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *LoadbalanceEntryAllowedSourcesItems0) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *LoadbalanceEntryAllowedSourcesItems0) UnmarshalBinary(b []byte) error { + var res LoadbalanceEntryAllowedSourcesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} + // LoadbalanceEntryEndpointsItems0 loadbalance entry endpoints items0 // // swagger:model LoadbalanceEntryEndpointsItems0 diff --git a/api/restapi/embedded_spec.go b/api/restapi/embedded_spec.go index 6349ab66f..1270a0b55 100644 --- a/api/restapi/embedded_spec.go +++ b/api/restapi/embedded_spec.go @@ -5067,6 +5067,18 @@ func init() { "LoadbalanceEntry": { "type": "object", "properties": { + "allowedSources": { + "description": "values of allowed source IP", + "type": "array", + "items": { + "properties": { + "prefix": { + "description": "IP address for allowed source access", + "type": "string" + } + } + } + }, "endpoints": { "description": "values of End point servers", "type": "array", @@ -11350,6 +11362,13 @@ func init() { "LoadbalanceEntry": { "type": "object", "properties": { + "allowedSources": { + "description": "values of allowed source IP", + "type": "array", + "items": { + "$ref": "#/definitions/LoadbalanceEntryAllowedSourcesItems0" + } + }, "endpoints": { "description": "values of End point servers", "type": "array", @@ -11467,6 +11486,14 @@ func init() { } } }, + "LoadbalanceEntryAllowedSourcesItems0": { + "properties": { + "prefix": { + "description": "IP address for allowed source access", + "type": "string" + } + } + }, "LoadbalanceEntryEndpointsItems0": { "properties": { "counter": { diff --git a/api/restapi/handler/cluster.go b/api/restapi/handler/cluster.go index 28927fe11..e04cb436e 100644 --- a/api/restapi/handler/cluster.go +++ b/api/restapi/handler/cluster.go @@ -28,7 +28,7 @@ import ( func ConfigGetCIState(params operations.GetConfigCistateAllParams) middleware.Responder { var result []*models.CIStatusGetEntry result = make([]*models.CIStatusGetEntry, 0) - tk.LogIt(tk.LogDebug, "api: Status %s API called. url : %s\n", params.HTTPRequest.Method, params.HTTPRequest.URL) + tk.LogIt(tk.LogTrace, "api: Status %s API called. url : %s\n", params.HTTPRequest.Method, params.HTTPRequest.URL) hasMod, err := ApiHooks.NetCIStateGet() if err != nil { tk.LogIt(tk.LogDebug, "api: Error occur : %v\n", err) diff --git a/api/restapi/handler/loadbalancer.go b/api/restapi/handler/loadbalancer.go index 81bf36924..3ac644e1c 100644 --- a/api/restapi/handler/loadbalancer.go +++ b/api/restapi/handler/loadbalancer.go @@ -58,6 +58,12 @@ func ConfigPostLoadbalancer(params operations.PostConfigLoadbalancerParams) midd } } + for _, data := range params.Attr.AllowedSources { + lbRules.SrcIPs = append(lbRules.SrcIPs, cmn.LbAllowedSrcIPArg{ + Prefix: data.Prefix, + }) + } + for _, data := range params.Attr.Endpoints { lbRules.Eps = append(lbRules.Eps, cmn.LbEndPointArg{ EpIP: data.EndpointIP, @@ -176,6 +182,12 @@ func ConfigGetLoadbalancer(params operations.GetConfigLoadbalancerAllParams) mid tmpLB.SecondaryIPs = append(tmpLB.SecondaryIPs, tmpSIP) } + for _, src := range lb.SrcIPs { + tmpSIP := new(models.LoadbalanceEntryAllowedSourcesItems0) + tmpSIP.Prefix = src.Prefix + tmpLB.AllowedSources = append(tmpLB.AllowedSources, tmpSIP) + } + // Endpoints match for _, ep := range lb.Eps { tmpEp := new(models.LoadbalanceEntryEndpointsItems0) diff --git a/api/restapi/handler/prometheus.go b/api/restapi/handler/prometheus.go index 5d0788898..c642e4a22 100644 --- a/api/restapi/handler/prometheus.go +++ b/api/restapi/handler/prometheus.go @@ -29,7 +29,7 @@ import ( ) func ConfigGetPrometheusCounter(params operations.GetMetricsParams) middleware.Responder { - tk.LogIt(tk.LogDebug, "api: Prometheus %s API called. url : %s\n", params.HTTPRequest.Method, params.HTTPRequest.URL) + tk.LogIt(tk.LogTrace, "api: Prometheus %s API called. url : %s\n", params.HTTPRequest.Method, params.HTTPRequest.URL) if !options.Opts.Prometheus { return operations.NewGetMetricsOK().WithPayload("Prometheus option is disabled.") } @@ -39,7 +39,7 @@ func ConfigGetPrometheusCounter(params operations.GetMetricsParams) middleware.R } func ConfigGetPrometheusOption(params operations.GetConfigMetricsParams) middleware.Responder { - tk.LogIt(tk.LogDebug, "[API] Prometheus %s API called. url : %s\n", params.HTTPRequest.Method, params.HTTPRequest.URL) + tk.LogIt(tk.LogTrace, "[API] Prometheus %s API called. url : %s\n", params.HTTPRequest.Method, params.HTTPRequest.URL) return operations.NewGetConfigMetricsOK().WithPayload(&models.MetricsConfig{Prometheus: &options.Opts.Prometheus}) } @@ -54,7 +54,7 @@ func ConfigPostPrometheus(params operations.PostConfigMetricsParams) middleware. } func ConfigDeletePrometheus(params operations.DeleteConfigMetricsParams) middleware.Responder { - tk.LogIt(tk.LogDebug, "[API] Prometheus %s API called. url : %s\n", params.HTTPRequest.Method, params.HTTPRequest.URL) + tk.LogIt(tk.LogTrace, "[API] Prometheus %s API called. url : %s\n", params.HTTPRequest.Method, params.HTTPRequest.URL) err := prometheus.Off() if err != nil { tk.LogIt(tk.LogDebug, "[API] Error occur : %v\n", err) diff --git a/api/swagger.yml b/api/swagger.yml index eace2bbef..a2a7843f1 100644 --- a/api/swagger.yml +++ b/api/swagger.yml @@ -3068,6 +3068,15 @@ definitions: secondaryIP: type: string description: IP address for secondary access + + allowedSources: + type: array + description: values of allowed source IP + items: + properties: + prefix: + type: string + description: IP address for allowed source access RouteEntry: type: object diff --git a/common/common.go b/common/common.go index 1f5069dcd..2c6b2a091 100644 --- a/common/common.go +++ b/common/common.go @@ -616,6 +616,8 @@ type LbRuleMod struct { Serv LbServiceArg `json:"serviceArguments"` // SecIPs - Secondary IPs for SCTP multi-homed service SecIPs []LbSecIPArg `json:"secondaryIPs"` + // SrcIPs - Allowed Source IPs + SrcIPs []LbAllowedSrcIPArg `json:"allowedSources"` // Eps - slice containing LbEndPointArg Eps []LbEndPointArg `json:"endpoints"` } diff --git a/loxilb-ebpf b/loxilb-ebpf index fb08f59fc..2f8fa81f8 160000 --- a/loxilb-ebpf +++ b/loxilb-ebpf @@ -1 +1 @@ -Subproject commit fb08f59fcdd21b9f5a918d3c42e7763cafaae112 +Subproject commit 2f8fa81f8b6c397c3afd4d5034e806f8d4301fd7 diff --git a/pkg/loxinet/apiclient.go b/pkg/loxinet/apiclient.go index 16691ad4b..d168092a5 100644 --- a/pkg/loxinet/apiclient.go +++ b/pkg/loxinet/apiclient.go @@ -18,7 +18,6 @@ package loxinet import ( "errors" - cmn "github.com/loxilb-io/loxilb/common" tk "github.com/loxilb-io/loxilib" ) @@ -332,7 +331,7 @@ func (na *NetAPIStruct) NetLbRuleAdd(lm *cmn.LbRuleMod) (int, error) { mh.mtx.Lock() defer mh.mtx.Unlock() var ips []string - ret, err := mh.zr.Rules.AddLbRule(lm.Serv, lm.SecIPs[:], nil, lm.Eps[:]) + ret, err := mh.zr.Rules.AddLbRule(lm.Serv, lm.SecIPs[:], lm.SrcIPs[:], lm.Eps[:]) if err == nil && lm.Serv.Bgp { if mh.bgp != nil { ips = append(ips, lm.Serv.ServIP) diff --git a/pkg/loxinet/dpebpf_linux.go b/pkg/loxinet/dpebpf_linux.go index 2fb301a0c..0d8a0595c 100644 --- a/pkg/loxinet/dpebpf_linux.go +++ b/pkg/loxinet/dpebpf_linux.go @@ -955,7 +955,7 @@ func DpLBRuleMod(w *LBDpWorkQ) int { key.mark = C.uint(w.BlockNum) if w.NatType == DpSnat { - key.mark |= SrcChkFwMark + key.mark |= SnatFwMark } else { key.daddr = [4]C.uint{0, 0, 0, 0} if tk.IsNetIPv4(w.ServiceIP.String()) { @@ -969,6 +969,7 @@ func DpLBRuleMod(w *LBDpWorkQ) int { key.dport = C.ushort(tk.Htons(w.L4Port)) key.l4proto = C.ushort(w.Proto) key.zone = C.ushort(w.ZoneNum) + } dat := new(proxyActs) @@ -1823,10 +1824,11 @@ func (e *DpEbpfH) DpFwRuleMod(w *FwDpWorkQ) int { } else if w.FwType == DpFwTrap { fwe.fwa.ca.act_type = C.DP_SET_TOCP } - fwe.fwa.ca.mark = C.ushort(w.FwVal2) + fwe.fwa.ca.mark = C.uint(w.FwVal2) if w.FwRecord { fwe.fwa.ca.record = C.ushort(1) } + ret := C.llb_add_map_elem(C.LL_DP_FW4_MAP, unsafe.Pointer(fwe), unsafe.Pointer(nil)) if ret != 0 { tk.LogIt(tk.LogError, "ebpf fw error\n") @@ -1986,7 +1988,7 @@ func dpCTMapNotifierWorker(cti *DpCtInfo) { mh.dpEbpf.mtx.Lock() defer mh.dpEbpf.mtx.Unlock() - if addOp == false { + if !addOp { cti = mh.dpEbpf.ctMap[cti.Key()] if cti == nil || cti.Deleted > 0 { return diff --git a/pkg/loxinet/rules.go b/pkg/loxinet/rules.go index a656a9846..62f2715a8 100644 --- a/pkg/loxinet/rules.go +++ b/pkg/loxinet/rules.go @@ -827,6 +827,10 @@ func (R *RuleH) GetLBRule() ([]cmn.LbRuleMod, error) { ret.SecIPs = append(ret.SecIPs, cmn.LbSecIPArg{SecIP: sip.sIP.String()}) } + for _, src := range data.srcList { + ret.SrcIPs = append(ret.SrcIPs, cmn.LbAllowedSrcIPArg{Prefix: src.srcPref.String()}) + } + data.DP(DpStatsGetImm) // Make Endpoints @@ -1495,8 +1499,6 @@ func (R *RuleH) AddLbRule(serv cmn.LbServiceArg, servSecIPs []cmn.LbSecIPArg, al return RuleUnknownServiceErr, errors.New("malformed-service error") } - allowedSources = append(allowedSources, cmn.LbAllowedSrcIPArg{Prefix: "10.10.10.1/32"}) - privIP = nil if serv.PrivateIP != "" { privIP = net.ParseIP(serv.PrivateIP) @@ -2076,8 +2078,7 @@ func (R *RuleH) AddFwRule(fwRule cmn.FwRuleArg, fwOptArgs cmn.FwOptArg) (int, er return RuleArgsErr, errors.New("rule-snat error") } - fwOpts.opt.fwMark = uint32(uint16((r.ruleNum) | SnatFwMark)) - + fwOpts.opt.fwMark = uint32(r.ruleNum) | SnatFwMark } tk.LogIt(tk.LogDebug, "fw-rule added - %d:%s-%s\n", r.ruleNum, r.tuples.String(), r.act.String())