From 342cc5f46a0053e466ccf58bd044cb7f5dc9a894 Mon Sep 17 00:00:00 2001 From: pudelkoM Date: Mon, 31 Jan 2022 19:10:48 -0800 Subject: [PATCH 01/18] WIP Add ternary port ranges Rename to `portFilter` Use new API --- pfcpiface/bess.go | 140 ++++++++------ pfcpiface/p4rt_translator.go | 8 +- pfcpiface/parse-pdr.go | 262 +++++++++++++++++++++---- pfcpiface/parse-pdr_test.go | 364 +++++++++++++++++++++++++++++++++++ pfcpiface/parse-sdf.go | 21 +- pfcpiface/up4.go | 6 +- 6 files changed, 684 insertions(+), 117 deletions(-) create mode 100644 pfcpiface/parse-pdr_test.go diff --git a/pfcpiface/bess.go b/pfcpiface/bess.go index 05f3d98e0..997f0f330 100644 --- a/pfcpiface/bess.go +++ b/pfcpiface/bess.go @@ -711,45 +711,55 @@ func (b *bess) addPDR(ctx context.Context, done chan<- bool, p pdr) { break } - f := &pb.WildcardMatchCommandAddArg{ - Gate: uint64(p.needDecap), - Priority: int64(math.MaxUint32 - p.precedence), - Values: []*pb.FieldData{ - intEnc(uint64(p.srcIface)), /* src_iface */ - intEnc(uint64(p.tunnelIP4Dst)), /* tunnel_ipv4_dst */ - intEnc(uint64(p.tunnelTEID)), /* enb_teid */ - intEnc(uint64(p.appFilter.srcIP)), /* ueaddr ip*/ - intEnc(uint64(p.appFilter.dstIP)), /* inet ip */ - intEnc(uint64(p.appFilter.srcPort)), /* ue port */ - intEnc(uint64(p.appFilter.dstPort)), /* inet port */ - intEnc(uint64(p.appFilter.proto)), /* proto id */ - }, - Masks: []*pb.FieldData{ - intEnc(uint64(p.srcIfaceMask)), /* src_iface-mask */ - intEnc(uint64(p.tunnelIP4DstMask)), /* tunnel_ipv4_dst-mask */ - intEnc(uint64(p.tunnelTEIDMask)), /* enb_teid-mask */ - intEnc(uint64(p.appFilter.srcIPMask)), /* ueaddr ip-mask */ - intEnc(uint64(p.appFilter.dstIPMask)), /* inet ip-mask */ - intEnc(uint64(p.appFilter.srcPortMask)), /* ue port-mask */ - intEnc(uint64(p.appFilter.dstPortMask)), /* inet port-mask */ - intEnc(uint64(p.appFilter.protoMask)), /* proto id-mask */ - }, - Valuesv: []*pb.FieldData{ - intEnc(uint64(p.pdrID)), /* pdr-id */ - intEnc(p.fseID), /* fseid */ - intEnc(uint64(p.ctrID)), /* ctr_id */ - intEnc(uint64(qerID)), /* qer_id */ - intEnc(uint64(p.farID)), /* far_id */ - }, - } - - any, err = anypb.New(f) + // Translate port ranges into ternary rule(s) and insert them one-by-one. + portRules, err := convertPortFiltersToTernary(p.appFilter.srcPortFilter, p.appFilter.dstPortFilter) if err != nil { - log.Println("Error marshalling the rule", f, err) + log.Errorln(err) return } + log.Warnln("PDR rules", portRules) + + for _, r := range portRules { + f := &pb.WildcardMatchCommandAddArg{ + Gate: uint64(p.needDecap), + Priority: int64(math.MaxUint32 - p.precedence), + Values: []*pb.FieldData{ + intEnc(uint64(p.srcIface)), /* src_iface */ + intEnc(uint64(p.tunnelIP4Dst)), /* tunnel_ipv4_dst */ + intEnc(uint64(p.tunnelTEID)), /* enb_teid */ + intEnc(uint64(p.appFilter.srcIP)), /* ueaddr ip*/ + intEnc(uint64(p.appFilter.dstIP)), /* inet ip */ + intEnc(uint64(r.srcPort)), /* ue port */ + intEnc(uint64(r.dstPort)), /* inet port */ + intEnc(uint64(p.appFilter.proto)), /* proto id */ + }, + Masks: []*pb.FieldData{ + intEnc(uint64(p.srcIfaceMask)), /* src_iface-mask */ + intEnc(uint64(p.tunnelIP4DstMask)), /* tunnel_ipv4_dst-mask */ + intEnc(uint64(p.tunnelTEIDMask)), /* enb_teid-mask */ + intEnc(uint64(p.appFilter.srcIPMask)), /* ueaddr ip-mask */ + intEnc(uint64(p.appFilter.dstIPMask)), /* inet ip-mask */ + intEnc(uint64(r.srcMask)), /* ue port-mask */ + intEnc(uint64(r.dstMask)), /* inet port-mask */ + intEnc(uint64(p.appFilter.protoMask)), /* proto id-mask */ + }, + Valuesv: []*pb.FieldData{ + intEnc(uint64(p.pdrID)), /* pdr-id */ + intEnc(p.fseID), /* fseid */ + intEnc(uint64(p.ctrID)), /* ctr_id */ + intEnc(uint64(qerID)), /* qer_id */ + intEnc(uint64(p.farID)), /* far_id */ + }, + } + + any, err = anypb.New(f) + if err != nil { + log.Println("Error marshalling the rule", f, err) + return + } - b.processPDR(ctx, any, upfMsgTypeAdd) + b.processPDR(ctx, any, upfMsgTypeAdd) + } done <- true }() } @@ -761,36 +771,44 @@ func (b *bess) delPDR(ctx context.Context, done chan<- bool, p pdr) { err error ) - f := &pb.WildcardMatchCommandDeleteArg{ - Values: []*pb.FieldData{ - intEnc(uint64(p.srcIface)), /* src_iface */ - intEnc(uint64(p.tunnelIP4Dst)), /* tunnel_ipv4_dst */ - intEnc(uint64(p.tunnelTEID)), /* enb_teid */ - intEnc(uint64(p.appFilter.srcIP)), /* ueaddr ip*/ - intEnc(uint64(p.appFilter.dstIP)), /* inet ip */ - intEnc(uint64(p.appFilter.srcPort)), /* ue port */ - intEnc(uint64(p.appFilter.dstPort)), /* inet port */ - intEnc(uint64(p.appFilter.proto)), /* proto id */ - }, - Masks: []*pb.FieldData{ - intEnc(uint64(p.srcIfaceMask)), /* src_iface-mask */ - intEnc(uint64(p.tunnelIP4DstMask)), /* tunnel_ipv4_dst-mask */ - intEnc(uint64(p.tunnelTEIDMask)), /* enb_teid-mask */ - intEnc(uint64(p.appFilter.srcIPMask)), /* ueaddr ip-mask */ - intEnc(uint64(p.appFilter.dstIPMask)), /* inet ip-mask */ - intEnc(uint64(p.appFilter.srcPortMask)), /* ue port-mask */ - intEnc(uint64(p.appFilter.dstPortMask)), /* inet port-mask */ - intEnc(uint64(p.appFilter.protoMask)), /* proto id-mask */ - }, - } - - any, err = anypb.New(f) + // Translate port ranges into ternary rule(s) and insert them one-by-one. + portRules, err := convertPortFiltersToTernary(p.appFilter.srcPortFilter, p.appFilter.dstPortFilter) if err != nil { - log.Errorln("Error marshalling the rule", f, err) + log.Errorln(err) return } - b.processPDR(ctx, any, upfMsgTypeDel) + for _, r := range portRules { + f := &pb.WildcardMatchCommandDeleteArg{ + Values: []*pb.FieldData{ + intEnc(uint64(p.srcIface)), /* src_iface */ + intEnc(uint64(p.tunnelIP4Dst)), /* tunnel_ipv4_dst */ + intEnc(uint64(p.tunnelTEID)), /* enb_teid */ + intEnc(uint64(p.appFilter.srcIP)), /* ueaddr ip*/ + intEnc(uint64(p.appFilter.dstIP)), /* inet ip */ + intEnc(uint64(r.srcPort)), /* ue port */ + intEnc(uint64(r.dstPort)), /* inet port */ + intEnc(uint64(p.appFilter.proto)), /* proto id */ + }, + Masks: []*pb.FieldData{ + intEnc(uint64(p.srcIfaceMask)), /* src_iface-mask */ + intEnc(uint64(p.tunnelIP4DstMask)), /* tunnel_ipv4_dst-mask */ + intEnc(uint64(p.tunnelTEIDMask)), /* enb_teid-mask */ + intEnc(uint64(p.appFilter.srcIPMask)), /* ueaddr ip-mask */ + intEnc(uint64(p.appFilter.dstIPMask)), /* inet ip-mask */ + intEnc(uint64(r.srcMask)), /* ue port-mask */ + intEnc(uint64(r.dstMask)), /* inet port-mask */ + intEnc(uint64(p.appFilter.protoMask)), /* proto id-mask */ + }, + } + + any, err = anypb.New(f) + if err != nil { + log.Errorln("Error marshalling the rule", f, err) + return + } + b.processPDR(ctx, any, upfMsgTypeDel) + } done <- true }() } diff --git a/pfcpiface/p4rt_translator.go b/pfcpiface/p4rt_translator.go index bc776e633..b96020f17 100644 --- a/pfcpiface/p4rt_translator.go +++ b/pfcpiface/p4rt_translator.go @@ -518,15 +518,15 @@ func (t *P4rtTranslator) BuildApplicationsTableEntry(pdr pdr, internalAppID uint var ( appIP, appIPMask uint32 = 0, 0 - appPort uint16 = 0 + appPort portFilter ) if pdr.srcIface == access { appIP, appIPMask = pdr.appFilter.dstIP, pdr.appFilter.dstIPMask - appPort = pdr.appFilter.dstPort + appPort = pdr.appFilter.dstPortFilter } else if pdr.srcIface == core { appIP, appIPMask = pdr.appFilter.srcIP, pdr.appFilter.srcIPMask - appPort = pdr.appFilter.srcPort + appPort = pdr.appFilter.srcPortFilter } appProto, appProtoMask := pdr.appFilter.proto, pdr.appFilter.protoMask @@ -538,7 +538,7 @@ func (t *P4rtTranslator) BuildApplicationsTableEntry(pdr pdr, internalAppID uint } } - if appPort != 0 { + if !appPort.isWildcardMatch() { if err := t.withRangeMatchField(entry, FieldAppL4Port, appPort, appPort); err != nil { return nil, err } diff --git a/pfcpiface/parse-pdr.go b/pfcpiface/parse-pdr.go index ca55e11e2..0e3b62055 100644 --- a/pfcpiface/parse-pdr.go +++ b/pfcpiface/parse-pdr.go @@ -1,29 +1,225 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Intel Corporation +// Copyright 2022 Open Networking Foundation package main import ( "errors" "fmt" + "math" "net" log "github.com/sirupsen/logrus" "github.com/wmnsk/go-pfcp/ie" ) +// portFilter encapsulates a L4 port range as seen in SDF. +type portFilter struct { + portLow uint16 + portHigh uint16 +} + +func newWildcardPortFilter() portFilter { + return portFilter{ + portLow: 0, + portHigh: math.MaxUint16, + } +} + +func newExactMatchPortFilter(port uint16) portFilter { + return portFilter{ + portLow: port, + portHigh: port, + } +} + +func newRangeMatchPortFilter(low, high uint16) portFilter { + if low > high { + return portFilter{} + } + return portFilter{ + portLow: low, + portHigh: high, + } +} + +func (pr portFilter) String() string { + return fmt.Sprintf("{ %v - %v }", pr.portLow, pr.portHigh) +} + +func (pr portFilter) isWildcardMatch() bool { + return pr.portLow == 0 && pr.portHigh == math.MaxUint16 || + pr.portLow == 0 && pr.portHigh == 0 +} + +func (pr portFilter) isExactMatch() bool { + return pr.portLow == pr.portHigh && pr.portHigh != 0 +} + +func (pr portFilter) isRangeMatch() bool { + return !pr.isExactMatch() && !pr.isWildcardMatch() +} + +// Returns portFilter as an exact match, without checking if it is one. isExactMatch() must be true +// before calling asExactMatchUnchecked. +func (pr portFilter) asExactMatchUnchecked() portFilterTernaryRule { + return portFilterTernaryRule{port: pr.portLow, mask: math.MaxUint16} +} + +func (pr portFilter) asRangeMatchUnchecked() (uint16, uint16) { + return pr.portLow, pr.portHigh +} + +// Return portFilter as a trivial, single value and mask, ternary match. Will fail if conversion is +// not possible. +func (pr portFilter) asTrivialTernaryMatch() (portFilterTernaryRule, error) { + if pr.isWildcardMatch() { + return portFilterTernaryRule{0, 0}, nil + } else if pr.isExactMatch() { + return pr.asExactMatchUnchecked(), nil + } + + return portFilterTernaryRule{}, ErrInvalidArgumentWithReason("asTrivialTernaryMatch", pr, "not trivially convertible") +} + +// Returns portFilter as a list of ternary matches that cover the same range. +func (pr portFilter) asComplexTernaryMatches() ([]portFilterTernaryRule, error) { + rules := make([]portFilterTernaryRule, 0) + + // Fast path for exact matches which are trivial. + if pr.isExactMatch() { + rules = append(rules, pr.asExactMatchUnchecked()) + return rules, nil + } + + // Adapted from https://stackoverflow.com/a/66959276 + const limit = math.MaxUint16 + maxPort := func(port, mask uint16) uint16 { + xid := limit - mask + nid := port & mask + return nid + xid + } + + portMask := func(port, end uint16) uint16 { + bit := uint16(1) + mask := uint16(limit) + testMask := uint16(limit) + netPort := port & limit + maximumPort := maxPort(netPort, limit) + + for netPort > 0 && maximumPort < end { + netPort = port & testMask + if netPort < port { + break + } + maximumPort = maxPort(netPort, testMask) + if maximumPort <= end { + mask = testMask + } + testMask -= bit + bit <<= 1 + } + return mask + } + + port := uint32(pr.portLow) // Promote to higher bit width for greater-equals check. + for port <= uint32(pr.portHigh) { + mask := portMask(uint16(port), pr.portHigh) + rules = append(rules, portFilterTernaryRule{uint16(port), mask}) + port = uint32(maxPort(uint16(port), mask)) + 1 + } + + return rules, nil +} + +type portFilterTernaryRule struct { + port, mask uint16 +} + +func (pf portFilterTernaryRule) String() string { + return fmt.Sprintf("{0b%b & 0b%b}", pf.port, pf.mask) +} + +type portFilterTernaryCrossProduct struct { + srcPort, srcMask uint16 + dstPort, dstMask uint16 +} + +// Converts two port ranges into a list of ternary rules covering the same range. +func convertPortFiltersToTernary(src, dst portFilter) ([]portFilterTernaryCrossProduct, error) { + // A single range rule can result in multiple ternary ones. To cover the same range of packets, + // we need to create the cross product of src and dst rules. For now, we only allow one true + // range match to keep the complexity in check. + if src.isRangeMatch() && dst.isRangeMatch() { + return nil, ErrInvalidArgumentWithReason("convertPortFiltersToTernary", + src, "src and dst ports cannot both be a range match") + } + + rules := make([]portFilterTernaryCrossProduct, 0) + + if src.isRangeMatch() { + srcTernaryRules, err := src.asComplexTernaryMatches() + if err != nil { + return nil, err + } + dstTernary, err := dst.asTrivialTernaryMatch() + if err != nil { + return nil, err + } + for _, r := range srcTernaryRules { + p := portFilterTernaryCrossProduct{ + srcPort: r.port, srcMask: r.mask, + dstPort: dstTernary.port, dstMask: dstTernary.mask, + } + rules = append(rules, p) + } + } else if dst.isRangeMatch() { + dstTernaryRules, err := dst.asComplexTernaryMatches() + if err != nil { + return nil, err + } + srcTernary, err := src.asTrivialTernaryMatch() + if err != nil { + return nil, err + } + for _, r := range dstTernaryRules { + p := portFilterTernaryCrossProduct{ + srcPort: srcTernary.port, srcMask: srcTernary.mask, + dstPort: r.port, dstMask: r.mask, + } + rules = append(rules, p) + } + } else { + // Neither is range. Only one rule needed. + srcTernary, err := src.asTrivialTernaryMatch() + if err != nil { + return nil, err + } + dstTernary, err := dst.asTrivialTernaryMatch() + if err != nil { + return nil, err + } + p := portFilterTernaryCrossProduct{ + dstPort: dstTernary.port, dstMask: dstTernary.mask, + srcPort: srcTernary.port, srcMask: srcTernary.mask, + } + rules = append(rules, p) + } + + return rules, nil +} + type applicationFilter struct { - srcIP uint32 - dstIP uint32 - srcPort uint16 - dstPort uint16 - proto uint8 - - srcIPMask uint32 - dstIPMask uint32 - srcPortMask uint16 - dstPortMask uint16 - protoMask uint8 + srcIP uint32 + dstIP uint32 + srcPortFilter portFilter + dstPortFilter portFilter + proto uint8 + + srcIPMask uint32 + dstIPMask uint32 + protoMask uint8 } type pdr struct { @@ -58,13 +254,13 @@ func needAllocIP(ueIPaddr *ie.UEIPAddressFields) bool { } func (af applicationFilter) String() string { - return fmt.Sprintf("ApplicationFilter(srcIP=%v/%x, dstIP=%v/%x, proto=%v/%x, srcPort=%v/%x, dstPort=%v/%x)", + return fmt.Sprintf("ApplicationFilter(srcIP=%v/%x, dstIP=%v/%x, proto=%v/%x, srcPort=%v, dstPort=%v)", af.srcIP, af.srcIPMask, af.dstIP, af.dstIPMask, af.proto, - af.protoMask, af.srcPort, af.srcPortMask, af.dstPort, af.dstPortMask) + af.protoMask, af.srcPortFilter, af.dstPortFilter) } func (af applicationFilter) IsEmpty() bool { - return af.srcIP == 0 && af.dstIP == 0 && af.proto == 0 && af.srcPort == 0 && af.dstPort == 0 + return af.srcIP == 0 && af.dstIP == 0 && af.proto == 0 && af.srcPortFilter.isWildcardMatch() && af.dstPortFilter.isWildcardMatch() } func (p pdr) String() string { @@ -198,16 +394,8 @@ func (p *pdr) parsePDI(seid uint64, pdiIEs []*ie.IE, appPFDs map[string]appPFD, p.appFilter.dstIPMask = ipMask2int(ipf.dst.IPNet.Mask) p.appFilter.srcIP = ip2int(ipf.src.IPNet.IP) p.appFilter.srcIPMask = ipMask2int(ipf.src.IPNet.Mask) - - if ipf.dst.Port > 0 { - p.appFilter.dstPort = ipf.dst.Port - p.appFilter.dstPortMask = 0xffff - } - - if ipf.src.Port > 0 { - p.appFilter.srcPort = ipf.src.Port - p.appFilter.srcPortMask = 0xffff - } + p.appFilter.dstPortFilter = ipf.dst.ports + p.appFilter.srcPortFilter = ipf.src.ports break } @@ -244,35 +432,25 @@ func (p *pdr) parsePDI(seid uint64, pdiIEs []*ie.IE, appPFDs map[string]appPFD, p.appFilter.dstIPMask = ipMask2int(ipf.dst.IPNet.Mask) p.appFilter.srcIP = ip2int(ipf.src.IPNet.IP) p.appFilter.srcIPMask = ipMask2int(ipf.src.IPNet.Mask) - - if ipf.src.Port > 0 { - p.appFilter.srcPort, p.appFilter.srcPortMask = ipf.src.Port, 0xffff - } - - if ipf.dst.Port > 0 { - p.appFilter.dstPort, p.appFilter.dstPortMask = ipf.dst.Port, 0xffff - } + p.appFilter.dstPortFilter = ipf.dst.ports + p.appFilter.srcPortFilter = ipf.src.ports // FIXME: temporary workaround for SDF Filter, // remove once we meet spec compliance - p.appFilter.srcPort = p.appFilter.dstPort - p.appFilter.dstPort, p.appFilter.dstPortMask = 0, 0 // reset UE Port + p.appFilter.srcPortFilter = p.appFilter.dstPortFilter + p.appFilter.dstPortFilter = newWildcardPortFilter() } else if p.srcIface == access { p.appFilter.srcIP = ip2int(ipf.dst.IPNet.IP) p.appFilter.srcIPMask = ipMask2int(ipf.dst.IPNet.Mask) p.appFilter.dstIP = ip2int(ipf.src.IPNet.IP) p.appFilter.dstIPMask = ipMask2int(ipf.src.IPNet.Mask) - if ipf.dst.Port > 0 { - p.appFilter.srcPort, p.appFilter.srcPortMask = ipf.dst.Port, 0xffff - } - if ipf.src.Port > 0 { - p.appFilter.dstPort, p.appFilter.dstPortMask = ipf.src.Port, 0xffff - } + p.appFilter.dstPortFilter = ipf.dst.ports + p.appFilter.srcPortFilter = ipf.src.ports // FIXME: temporary workaround for SDF Filter, // remove once we meet spec compliance - p.appFilter.dstPort = p.appFilter.srcPort - p.appFilter.srcPort, p.appFilter.srcPortMask = 0, 0 // reset UE Port + p.appFilter.dstPortFilter = p.appFilter.srcPortFilter + p.appFilter.srcPortFilter = newWildcardPortFilter() } } } diff --git a/pfcpiface/parse-pdr_test.go b/pfcpiface/parse-pdr_test.go new file mode 100644 index 000000000..8978697e7 --- /dev/null +++ b/pfcpiface/parse-pdr_test.go @@ -0,0 +1,364 @@ +package main + +import ( + "math" + "reflect" + "testing" +) + +func Test_convertPortFiltersToTernary(t *testing.T) { + type args struct { + src portFilter + dst portFilter + } + tests := []struct { + name string + args args + want []portFilterTernaryCrossProduct + wantErr bool + }{ + {name: "exact ranges", + args: args{src: newExactMatchPortFilter(5000), dst: newExactMatchPortFilter(80)}, + want: []portFilterTernaryCrossProduct{{ + srcPort: 5000, + srcMask: math.MaxUint16, + dstPort: 80, + dstMask: math.MaxUint16, + }}, + wantErr: false}, + {name: "wildcard dst range", + args: args{src: newExactMatchPortFilter(10), dst: newWildcardPortFilter()}, + want: []portFilterTernaryCrossProduct{{ + srcPort: 10, + srcMask: math.MaxUint16, + dstPort: 0, + dstMask: 0, + }}, + wantErr: false}, + {name: "true range src range", + args: args{src: newRangeMatchPortFilter(1, 3), dst: newExactMatchPortFilter(80)}, + want: []portFilterTernaryCrossProduct{ + { + srcPort: 0x1, + srcMask: 0xffff, + dstPort: 80, + dstMask: math.MaxUint16, + }, + { + srcPort: 0x2, + srcMask: 0xfffe, + dstPort: 80, + dstMask: math.MaxUint16, + }}, + wantErr: false}, + {name: "invalid double range", + args: args{src: newRangeMatchPortFilter(10, 20), dst: newRangeMatchPortFilter(80, 85)}, + want: nil, + wantErr: true}, + } + for _, tt := range tests { + t.Run( + tt.name, func(t *testing.T) { + got, err := convertPortFiltersToTernary(tt.args.src, tt.args.dst) + if (err != nil) != tt.wantErr { + t.Errorf("convertPortFiltersToTernary() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("convertPortFiltersToTernary() got = %v, want %v", got, tt.want) + } + }, + ) + } +} + +func Test_newWildcardPortFilter(t *testing.T) { + tests := []struct { + name string + want portFilter + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run( + tt.name, func(t *testing.T) { + if got := newWildcardPortFilter(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("newWildcardPortFilter() = %v, want %v", got, tt.want) + } + }, + ) + } +} + +func Test_portFilter_String(t *testing.T) { + type fields struct { + PortLow uint16 + PortHigh uint16 + } + tests := []struct { + name string + fields fields + want string + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run( + tt.name, func(t *testing.T) { + pr := portFilter{ + portLow: tt.fields.PortLow, + portHigh: tt.fields.PortHigh, + } + if got := pr.String(); got != tt.want { + t.Errorf("String() = %v, want %v", got, tt.want) + } + }, + ) + } +} + +func Test_portFilter_isExactMatch(t *testing.T) { + type fields struct { + PortLow uint16 + PortHigh uint16 + } + tests := []struct { + name string + fields fields + want bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run( + tt.name, func(t *testing.T) { + pr := portFilter{ + portLow: tt.fields.PortLow, + portHigh: tt.fields.PortHigh, + } + if got := pr.isExactMatch(); got != tt.want { + t.Errorf("isExactMatch() = %v, want %v", got, tt.want) + } + }, + ) + } +} + +func Test_portFilter_isRangeMatch(t *testing.T) { + type fields struct { + PortLow uint16 + PortHigh uint16 + } + tests := []struct { + name string + fields fields + want bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run( + tt.name, func(t *testing.T) { + pr := portFilter{ + portLow: tt.fields.PortLow, + portHigh: tt.fields.PortHigh, + } + if got := pr.isRangeMatch(); got != tt.want { + t.Errorf("isRangeMatch() = %v, want %v", got, tt.want) + } + }, + ) + } +} + +func Test_portFilter_isWildcardMatch(t *testing.T) { + type fields struct { + PortLow uint16 + PortHigh uint16 + } + tests := []struct { + name string + fields fields + want bool + }{ + // TODO: Add test cases. + {name: "foo", fields: fields{ + PortLow: 0, + PortHigh: 0, + }, want: true}, + } + for _, tt := range tests { + t.Run( + tt.name, func(t *testing.T) { + pr := portFilter{ + portLow: tt.fields.PortLow, + portHigh: tt.fields.PortHigh, + } + if got := pr.isWildcardMatch(); got != tt.want { + t.Errorf("isWildcardMatch() = %v, want %v", got, tt.want) + } + }, + ) + } +} + +// Perform a ternary match of value against rules. +func matchesTernary(value uint16, rules []portFilterTernaryRule) bool { + for _, r := range rules { + if (value & r.mask) == r.port { + return true + } + } + return false +} + +func Test_portFilter_asComplexTernaryMatches(t *testing.T) { + tests := []struct { + name string + pr portFilter + wantErr bool + }{ + {name: "Exact match port range", + pr: portFilter{ + portLow: 8888, + portHigh: 8888, + }, + //want: []portFilterTernaryRule{ + // {port: 8888, mask: 0xffff}, + //}, + wantErr: false}, + {name: "wildcard port range", + pr: portFilter{ + portLow: 0, + portHigh: math.MaxUint16, + }, + wantErr: false}, + {name: "Simplest port range", + pr: portFilter{ + portLow: 0b0, // 0 + portHigh: 0b1, // 1 + }, + //want: []portFilterTernaryRule{ + // {port: 0b0, mask: 0xfffe}, + //}, + wantErr: false}, + {name: "Simplest port range2", + pr: portFilter{ + portLow: 0b01, // 1 + portHigh: 0b10, // 2 + }, + //want: []portFilterTernaryRule{ + // {port: 0b01, mask: 0xffff}, + // {port: 0b10, mask: 0xffff}, + //}, + wantErr: false}, + {name: "Trivial ternary port range", + pr: portFilter{ + portLow: 0x0100, // 256 + portHigh: 0x01ff, // 511 + }, + //want: []portFilterTernaryRule{ + // {port: 0x0100, mask: 0xff00}, + //}, + wantErr: false}, + {name: "one to three range", + pr: portFilter{ + portLow: 0b01, // 1 + portHigh: 0b11, // 3 + }, + //want: []portFilterTernaryRule{ + // {port: 0b01, mask: 0xffff}, + // {port: 0b10, mask: 0xfffe}, + //}, + wantErr: false}, + {name: "True port range", + pr: portFilter{ + portLow: 0b00010, // 2 + portHigh: 0b11101, // 29 + }, + wantErr: false}, + {name: "low port filter", + pr: portFilter{ + portLow: 0, + portHigh: 1023, + }, + wantErr: false}, + {name: "some app filter", + pr: portFilter{ + portLow: 8080, + portHigh: 8084, + }, + wantErr: false}, + } + for _, tt := range tests { + t.Run( + tt.name, func(t *testing.T) { + pr := portFilter{ + portLow: tt.pr.portLow, + portHigh: tt.pr.portHigh, + } + got, err := pr.asComplexTernaryMatches() + if (err != nil) != tt.wantErr { + t.Errorf("asComplexTernaryMatches() error = %v, wantErr %v", err, tt.wantErr) + return + } + //if !reflect.DeepEqual(got, tt.want) { + // t.Errorf("asComplexTernaryMatches() got = %v, want %v", got, tt.want) + //} + // Do exhaustive test over entire value range. + for port := 0; port <= math.MaxUint16; port++ { + expectMatch := port >= int(tt.pr.portLow) && port <= int(tt.pr.portHigh) + if matchesTernary(uint16(port), got) != expectMatch { + mod := " " + if !expectMatch { + mod = " not " + } + t.Errorf("Expected port %v to%vmatch against rules %v from range %+v", port, mod, got, tt.pr) + } + } + }, + ) + } +} + +func Test_portFilter_asTrivialTernaryMatch(t *testing.T) { + tests := []struct { + name string + pr portFilter + wantPort uint16 + wantMask uint16 + wantErr bool + }{ + {name: "Wildcard range", pr: portFilter{ + portLow: 0, + portHigh: 0, + }, wantPort: 0, wantMask: 0, wantErr: false}, + {name: "Exact match range", pr: portFilter{ + portLow: 100, + portHigh: 100, + }, wantPort: 100, wantMask: 0xffff, wantErr: false}, + {name: "True range match fail", pr: portFilter{ + portLow: 100, + portHigh: 200, + }, wantPort: 0, wantMask: 0, wantErr: true}, + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run( + tt.name, func(t *testing.T) { + got, err := tt.pr.asTrivialTernaryMatch() + if (err != nil) != tt.wantErr { + t.Errorf("asTrivialTernaryMatch() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if got.port != tt.wantPort { + t.Errorf("asTrivialTernaryMatch() got = %v, want %v", got.port, tt.wantPort) + } + if got.mask != tt.wantMask { + t.Errorf("asTrivialTernaryMatch() got = %v, want %v", got.mask, tt.wantMask) + } + }, + ) + } +} diff --git a/pfcpiface/parse-sdf.go b/pfcpiface/parse-sdf.go index 6362295bc..05649ba78 100644 --- a/pfcpiface/parse-sdf.go +++ b/pfcpiface/parse-sdf.go @@ -1,5 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Intel Corporation +// Copyright 2022 Open Networking Foundation package main @@ -21,7 +22,7 @@ var errBadFilterDesc = errors.New("unsupported Filter Description format") type endpoint struct { IPNet *net.IPNet - Port uint16 + ports portFilter } func (ep *endpoint) parseNet(ipnet string) error { @@ -66,12 +67,11 @@ func (ep *endpoint) parsePort(port string) error { return err } - // TODO: support port ranges - if low != high { - return ErrInvalidArgumentWithReason("port", port, "port ranges are not supported yet") + if low > high { + return ErrInvalidArgumentWithReason("port", port, "invalid port range") } - ep.Port = uint16(low) + ep.ports = newRangeMatchPortFilter(uint16(low), uint16(high)) return nil } @@ -82,10 +82,17 @@ type ipFilterRule struct { src, dst endpoint } +func newIpFilterRule() *ipFilterRule { + return &ipFilterRule{ + src: endpoint{ports: newWildcardPortFilter()}, + dst: endpoint{ports: newWildcardPortFilter()}, + } +} + func (ipf *ipFilterRule) String() string { return fmt.Sprintf("FlowDescription{action=%v, direction=%v, proto=%v, "+ "srcIP=%v, srcPort=%v, dstIP=%v, dstPort=%v}", - ipf.action, ipf.direction, ipf.proto, ipf.src.IPNet, ipf.src.Port, ipf.dst.IPNet, ipf.dst.Port) + ipf.action, ipf.direction, ipf.proto, ipf.src.IPNet, ipf.src.ports, ipf.dst.IPNet, ipf.dst.ports) } // "permit out ip from any to assigned" @@ -106,7 +113,7 @@ func parseFlowDesc(flowDesc, ueIP string) (*ipFilterRule, error) { }) parseLog.Debug("Parsing flow description") - ipf := &ipFilterRule{} + ipf := newIpFilterRule() fields := strings.Fields(flowDesc) diff --git a/pfcpiface/up4.go b/pfcpiface/up4.go index 084e6cf61..8c6a0ea7a 100644 --- a/pfcpiface/up4.go +++ b/pfcpiface/up4.go @@ -573,7 +573,7 @@ func (up4 *UP4) allocateInternalApplicationID(app application) (uint8, error) { func (up4 *UP4) releaseInternalApplicationID(appFilter applicationFilter) { app := application{ appIP: appFilter.srcIP, - appL4Port: appFilter.srcPort, + appL4Port: appFilter.srcPortFilter.asExactMatchUnchecked().port, appProto: appFilter.proto, } @@ -589,12 +589,12 @@ func (up4 *UP4) getOrAllocateInternalApplicationID(pdr pdr) (uint8, error) { if pdr.IsUplink() { app = application{ appIP: pdr.appFilter.dstIP, - appL4Port: pdr.appFilter.dstPort, + appL4Port: pdr.appFilter.dstPortFilter.asExactMatchUnchecked().port, } } else if pdr.IsDownlink() { app = application{ appIP: pdr.appFilter.srcIP, - appL4Port: pdr.appFilter.srcPort, + appL4Port: pdr.appFilter.srcPortFilter.asExactMatchUnchecked().port, } } From 86721efbfdb55334ecec08f5145a27725076c14f Mon Sep 17 00:00:00 2001 From: pudelkoM Date: Tue, 1 Feb 2022 14:41:30 -0800 Subject: [PATCH 02/18] Add test for zero `portFilter` --- pfcpiface/parse-pdr.go | 3 ++- pfcpiface/parse-pdr_test.go | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/pfcpiface/parse-pdr.go b/pfcpiface/parse-pdr.go index 0e3b62055..b3ee908c1 100644 --- a/pfcpiface/parse-pdr.go +++ b/pfcpiface/parse-pdr.go @@ -14,7 +14,8 @@ import ( "github.com/wmnsk/go-pfcp/ie" ) -// portFilter encapsulates a L4 port range as seen in SDF. +// portFilter encapsulates a L4 port range as seen in PDRs. A zero value portFilter represents +// a wildcard match, but use of the dedicated new*PortFilter() functions is encouraged. type portFilter struct { portLow uint16 portHigh uint16 diff --git a/pfcpiface/parse-pdr_test.go b/pfcpiface/parse-pdr_test.go index 8978697e7..bbf5df51f 100644 --- a/pfcpiface/parse-pdr_test.go +++ b/pfcpiface/parse-pdr_test.go @@ -1,6 +1,7 @@ package main import ( + "github.com/stretchr/testify/assert" "math" "reflect" "testing" @@ -72,6 +73,12 @@ func Test_convertPortFiltersToTernary(t *testing.T) { } } +func Test_defaultPortFilter(t *testing.T) { + t.Run("default constructed is wildcard", func(t *testing.T) { + assert.True(t, portFilter{}.isWildcardMatch(), "default portFilter is wildcard") + }) +} + func Test_newWildcardPortFilter(t *testing.T) { tests := []struct { name string From 00eb9a44e011e810d16aaaf54430e84247f0a0a8 Mon Sep 17 00:00:00 2001 From: pudelkoM Date: Tue, 1 Feb 2022 15:23:34 -0800 Subject: [PATCH 03/18] Shorten port filter string --- pfcpiface/parse-pdr.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pfcpiface/parse-pdr.go b/pfcpiface/parse-pdr.go index b3ee908c1..f0f520db1 100644 --- a/pfcpiface/parse-pdr.go +++ b/pfcpiface/parse-pdr.go @@ -46,7 +46,7 @@ func newRangeMatchPortFilter(low, high uint16) portFilter { } func (pr portFilter) String() string { - return fmt.Sprintf("{ %v - %v }", pr.portLow, pr.portHigh) + return fmt.Sprintf("{%v-%v}", pr.portLow, pr.portHigh) } func (pr portFilter) isWildcardMatch() bool { From f4bd068fca0b02a957500b5928b56a6da63e998d Mon Sep 17 00:00:00 2001 From: pudelkoM Date: Tue, 1 Feb 2022 15:45:46 -0800 Subject: [PATCH 04/18] More doc strings --- pfcpiface/parse-pdr.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pfcpiface/parse-pdr.go b/pfcpiface/parse-pdr.go index f0f520db1..5ccd6afc1 100644 --- a/pfcpiface/parse-pdr.go +++ b/pfcpiface/parse-pdr.go @@ -21,6 +21,8 @@ type portFilter struct { portHigh uint16 } +// newWildcardPortFilter returns a portFilter that matches on every possible port, i.e., implements +// no filtering. func newWildcardPortFilter() portFilter { return portFilter{ portLow: 0, @@ -28,6 +30,7 @@ func newWildcardPortFilter() portFilter { } } +// newExactMatchPortFilter returns a portFilter that matches on exactly the given port. func newExactMatchPortFilter(port uint16) portFilter { return portFilter{ portLow: port, @@ -35,6 +38,9 @@ func newExactMatchPortFilter(port uint16) portFilter { } } +// newRangeMatchPortFilter returns a portFilter that matches on the given range [low, high]. +// low must be smaller than high. Creating exact and wildcard matches with this function is +// possible, but use of the dedicated functions is encouraged. func newRangeMatchPortFilter(low, high uint16) portFilter { if low > high { return portFilter{} @@ -45,6 +51,18 @@ func newRangeMatchPortFilter(low, high uint16) portFilter { } } +// newTernaryMatchPortFilter returns a portFilter that matches on the given port and mask. Only +// trivial mask are supported. +func newTernaryMatchPortFilter(port, mask uint16) (portFilter, error) { + if mask == 0 { + return newWildcardPortFilter(), nil + } else if mask == math.MaxUint16 { + return newExactMatchPortFilter(port), nil + } else { + return portFilter{}, ErrInvalidArgument("newTernaryMatchPortFilter", mask) + } +} + func (pr portFilter) String() string { return fmt.Sprintf("{%v-%v}", pr.portLow, pr.portHigh) } From 2411c64d2f3285a557a1b480d942f3074842f7a2 Mon Sep 17 00:00:00 2001 From: pudelkoM Date: Tue, 1 Feb 2022 16:04:56 -0800 Subject: [PATCH 05/18] Fix typo --- pfcpiface/parse-pdr.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pfcpiface/parse-pdr.go b/pfcpiface/parse-pdr.go index 5ccd6afc1..f7b0cee45 100644 --- a/pfcpiface/parse-pdr.go +++ b/pfcpiface/parse-pdr.go @@ -168,7 +168,7 @@ type portFilterTernaryCrossProduct struct { // Converts two port ranges into a list of ternary rules covering the same range. func convertPortFiltersToTernary(src, dst portFilter) ([]portFilterTernaryCrossProduct, error) { // A single range rule can result in multiple ternary ones. To cover the same range of packets, - // we need to create the cross product of src and dst rules. For now, we only allow one true + // we need to create the Cartesian product of src and dst rules. For now, we only allow one true // range match to keep the complexity in check. if src.isRangeMatch() && dst.isRangeMatch() { return nil, ErrInvalidArgumentWithReason("convertPortFiltersToTernary", From fba124f4270eb96a22d714ddd0863e224ab7573c Mon Sep 17 00:00:00 2001 From: pudelkoM Date: Wed, 2 Feb 2022 10:34:45 -0800 Subject: [PATCH 06/18] Rename product and enable `want` test check --- pfcpiface/parse-pdr.go | 18 +++++++++++------- pfcpiface/parse-pdr_test.go | 24 ++++++++++++++---------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/pfcpiface/parse-pdr.go b/pfcpiface/parse-pdr.go index f7b0cee45..52cb09da7 100644 --- a/pfcpiface/parse-pdr.go +++ b/pfcpiface/parse-pdr.go @@ -106,11 +106,15 @@ func (pr portFilter) asTrivialTernaryMatch() (portFilterTernaryRule, error) { func (pr portFilter) asComplexTernaryMatches() ([]portFilterTernaryRule, error) { rules := make([]portFilterTernaryRule, 0) - // Fast path for exact matches which are trivial. + // Fast path for exact and wildcard matches which are trivial. if pr.isExactMatch() { rules = append(rules, pr.asExactMatchUnchecked()) return rules, nil } + if pr.isWildcardMatch() { + rules = append(rules, portFilterTernaryRule{0, 0}) + return rules, nil + } // Adapted from https://stackoverflow.com/a/66959276 const limit = math.MaxUint16 @@ -160,13 +164,13 @@ func (pf portFilterTernaryRule) String() string { return fmt.Sprintf("{0b%b & 0b%b}", pf.port, pf.mask) } -type portFilterTernaryCrossProduct struct { +type portFilterTernaryCartesianProduct struct { srcPort, srcMask uint16 dstPort, dstMask uint16 } // Converts two port ranges into a list of ternary rules covering the same range. -func convertPortFiltersToTernary(src, dst portFilter) ([]portFilterTernaryCrossProduct, error) { +func convertPortFiltersToTernary(src, dst portFilter) ([]portFilterTernaryCartesianProduct, error) { // A single range rule can result in multiple ternary ones. To cover the same range of packets, // we need to create the Cartesian product of src and dst rules. For now, we only allow one true // range match to keep the complexity in check. @@ -175,7 +179,7 @@ func convertPortFiltersToTernary(src, dst portFilter) ([]portFilterTernaryCrossP src, "src and dst ports cannot both be a range match") } - rules := make([]portFilterTernaryCrossProduct, 0) + rules := make([]portFilterTernaryCartesianProduct, 0) if src.isRangeMatch() { srcTernaryRules, err := src.asComplexTernaryMatches() @@ -187,7 +191,7 @@ func convertPortFiltersToTernary(src, dst portFilter) ([]portFilterTernaryCrossP return nil, err } for _, r := range srcTernaryRules { - p := portFilterTernaryCrossProduct{ + p := portFilterTernaryCartesianProduct{ srcPort: r.port, srcMask: r.mask, dstPort: dstTernary.port, dstMask: dstTernary.mask, } @@ -203,7 +207,7 @@ func convertPortFiltersToTernary(src, dst portFilter) ([]portFilterTernaryCrossP return nil, err } for _, r := range dstTernaryRules { - p := portFilterTernaryCrossProduct{ + p := portFilterTernaryCartesianProduct{ srcPort: srcTernary.port, srcMask: srcTernary.mask, dstPort: r.port, dstMask: r.mask, } @@ -219,7 +223,7 @@ func convertPortFiltersToTernary(src, dst portFilter) ([]portFilterTernaryCrossP if err != nil { return nil, err } - p := portFilterTernaryCrossProduct{ + p := portFilterTernaryCartesianProduct{ dstPort: dstTernary.port, dstMask: dstTernary.mask, srcPort: srcTernary.port, srcMask: srcTernary.mask, } diff --git a/pfcpiface/parse-pdr_test.go b/pfcpiface/parse-pdr_test.go index bbf5df51f..03047ae06 100644 --- a/pfcpiface/parse-pdr_test.go +++ b/pfcpiface/parse-pdr_test.go @@ -15,12 +15,12 @@ func Test_convertPortFiltersToTernary(t *testing.T) { tests := []struct { name string args args - want []portFilterTernaryCrossProduct + want []portFilterTernaryCartesianProduct wantErr bool }{ {name: "exact ranges", args: args{src: newExactMatchPortFilter(5000), dst: newExactMatchPortFilter(80)}, - want: []portFilterTernaryCrossProduct{{ + want: []portFilterTernaryCartesianProduct{{ srcPort: 5000, srcMask: math.MaxUint16, dstPort: 80, @@ -29,7 +29,7 @@ func Test_convertPortFiltersToTernary(t *testing.T) { wantErr: false}, {name: "wildcard dst range", args: args{src: newExactMatchPortFilter(10), dst: newWildcardPortFilter()}, - want: []portFilterTernaryCrossProduct{{ + want: []portFilterTernaryCartesianProduct{{ srcPort: 10, srcMask: math.MaxUint16, dstPort: 0, @@ -38,7 +38,7 @@ func Test_convertPortFiltersToTernary(t *testing.T) { wantErr: false}, {name: "true range src range", args: args{src: newRangeMatchPortFilter(1, 3), dst: newExactMatchPortFilter(80)}, - want: []portFilterTernaryCrossProduct{ + want: []portFilterTernaryCartesianProduct{ { srcPort: 0x1, srcMask: 0xffff, @@ -224,21 +224,25 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { name string pr portFilter wantErr bool + want []portFilterTernaryRule }{ {name: "Exact match port range", pr: portFilter{ portLow: 8888, portHigh: 8888, }, - //want: []portFilterTernaryRule{ - // {port: 8888, mask: 0xffff}, - //}, + want: []portFilterTernaryRule{ + {port: 8888, mask: 0xffff}, + }, wantErr: false}, {name: "wildcard port range", pr: portFilter{ portLow: 0, portHigh: math.MaxUint16, }, + want: []portFilterTernaryRule{ + {port: 0, mask: 0}, + }, wantErr: false}, {name: "Simplest port range", pr: portFilter{ @@ -309,9 +313,9 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { t.Errorf("asComplexTernaryMatches() error = %v, wantErr %v", err, tt.wantErr) return } - //if !reflect.DeepEqual(got, tt.want) { - // t.Errorf("asComplexTernaryMatches() got = %v, want %v", got, tt.want) - //} + if tt.want != nil && !reflect.DeepEqual(got, tt.want) { + t.Errorf("asComplexTernaryMatches() got = %v, want %v", got, tt.want) + } // Do exhaustive test over entire value range. for port := 0; port <= math.MaxUint16; port++ { expectMatch := port >= int(tt.pr.portLow) && port <= int(tt.pr.portHigh) From 0d6fd96cafdd04a2cc6af30a6d137e7b978923d4 Mon Sep 17 00:00:00 2001 From: pudelkoM Date: Wed, 2 Feb 2022 13:24:30 -0800 Subject: [PATCH 07/18] Add `portFilter.Width` function --- pfcpiface/parse-pdr.go | 10 ++++++++++ pfcpiface/parse-pdr_test.go | 31 ++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/pfcpiface/parse-pdr.go b/pfcpiface/parse-pdr.go index 52cb09da7..8cb373086 100644 --- a/pfcpiface/parse-pdr.go +++ b/pfcpiface/parse-pdr.go @@ -67,6 +67,16 @@ func (pr portFilter) String() string { return fmt.Sprintf("{%v-%v}", pr.portLow, pr.portHigh) } +// Width returns the number of ports covered by this portFilter. +func (pr portFilter) Width() uint16 { + // Need to handle the zero value. + if pr.isWildcardMatch() { + return math.MaxUint16 + } else { + return pr.portHigh - pr.portLow + 1 + } +} + func (pr portFilter) isWildcardMatch() bool { return pr.portLow == 0 && pr.portHigh == math.MaxUint16 || pr.portLow == 0 && pr.portHigh == 0 diff --git a/pfcpiface/parse-pdr_test.go b/pfcpiface/parse-pdr_test.go index 03047ae06..ad3758c7a 100644 --- a/pfcpiface/parse-pdr_test.go +++ b/pfcpiface/parse-pdr_test.go @@ -288,13 +288,19 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { portHigh: 0b11101, // 29 }, wantErr: false}, + {name: "Worst case port range", + pr: portFilter{ + portLow: 1, + portHigh: 65534, + }, + wantErr: false}, {name: "low port filter", pr: portFilter{ portLow: 0, portHigh: 1023, }, wantErr: false}, - {name: "some app filter", + {name: "some small app filter", pr: portFilter{ portLow: 8080, portHigh: 8084, @@ -373,3 +379,26 @@ func Test_portFilter_asTrivialTernaryMatch(t *testing.T) { ) } } + +func Test_portFilter_Width(t *testing.T) { + tests := []struct { + name string + pr portFilter + want uint16 + }{ + {name: "wildcard", pr: newWildcardPortFilter(), want: math.MaxUint16}, + {name: "zero value", pr: portFilter{}, want: math.MaxUint16}, + {name: "exact match", pr: newExactMatchPortFilter(100), want: 1}, + {name: "range match", pr: newRangeMatchPortFilter(10, 12), want: 3}, + {name: "range single match", pr: newRangeMatchPortFilter(1000, 1000), want: 1}, + } + for _, tt := range tests { + t.Run( + tt.name, func(t *testing.T) { + if got := tt.pr.Width(); got != tt.want { + t.Errorf("Width() = %v, want %v", got, tt.want) + } + }, + ) + } +} From 63f15defe1f658021348cbc6251b5c729e984d80 Mon Sep 17 00:00:00 2001 From: pudelkoM Date: Wed, 2 Feb 2022 15:10:46 -0800 Subject: [PATCH 08/18] Implement exact range conversion --- pfcpiface/parse-pdr.go | 84 ++++++++++++++++++++++--------------- pfcpiface/parse-pdr_test.go | 10 ++++- 2 files changed, 58 insertions(+), 36 deletions(-) diff --git a/pfcpiface/parse-pdr.go b/pfcpiface/parse-pdr.go index 8cb373086..1160eeb93 100644 --- a/pfcpiface/parse-pdr.go +++ b/pfcpiface/parse-pdr.go @@ -112,8 +112,16 @@ func (pr portFilter) asTrivialTernaryMatch() (portFilterTernaryRule, error) { return portFilterTernaryRule{}, ErrInvalidArgumentWithReason("asTrivialTernaryMatch", pr, "not trivially convertible") } +type RangeConversionStrategy int + +const ( + Exact RangeConversionStrategy = iota + Ternary + Hybrid +) + // Returns portFilter as a list of ternary matches that cover the same range. -func (pr portFilter) asComplexTernaryMatches() ([]portFilterTernaryRule, error) { +func (pr portFilter) asComplexTernaryMatches(strategy RangeConversionStrategy) ([]portFilterTernaryRule, error) { rules := make([]portFilterTernaryRule, 0) // Fast path for exact and wildcard matches which are trivial. @@ -126,41 +134,49 @@ func (pr portFilter) asComplexTernaryMatches() ([]portFilterTernaryRule, error) return rules, nil } - // Adapted from https://stackoverflow.com/a/66959276 - const limit = math.MaxUint16 - maxPort := func(port, mask uint16) uint16 { - xid := limit - mask - nid := port & mask - return nid + xid - } + if strategy == Ternary { + // Adapted from https://stackoverflow.com/a/66959276 + const limit = math.MaxUint16 + maxPort := func(port, mask uint16) uint16 { + xid := limit - mask + nid := port & mask + return nid + xid + } - portMask := func(port, end uint16) uint16 { - bit := uint16(1) - mask := uint16(limit) - testMask := uint16(limit) - netPort := port & limit - maximumPort := maxPort(netPort, limit) - - for netPort > 0 && maximumPort < end { - netPort = port & testMask - if netPort < port { - break - } - maximumPort = maxPort(netPort, testMask) - if maximumPort <= end { - mask = testMask + portMask := func(port, end uint16) uint16 { + bit := uint16(1) + mask := uint16(limit) + testMask := uint16(limit) + netPort := port & limit + maximumPort := maxPort(netPort, limit) + + for netPort > 0 && maximumPort < end { + netPort = port & testMask + if netPort < port { + break + } + maximumPort = maxPort(netPort, testMask) + if maximumPort <= end { + mask = testMask + } + testMask -= bit + bit <<= 1 } - testMask -= bit - bit <<= 1 + return mask } - return mask - } - port := uint32(pr.portLow) // Promote to higher bit width for greater-equals check. - for port <= uint32(pr.portHigh) { - mask := portMask(uint16(port), pr.portHigh) - rules = append(rules, portFilterTernaryRule{uint16(port), mask}) - port = uint32(maxPort(uint16(port), mask)) + 1 + port := uint32(pr.portLow) // Promote to higher bit width for greater-equals check. + for port <= uint32(pr.portHigh) { + mask := portMask(uint16(port), pr.portHigh) + rules = append(rules, portFilterTernaryRule{uint16(port), mask}) + port = uint32(maxPort(uint16(port), mask)) + 1 + } + } else if strategy == Exact { + for port := int(pr.portLow); port <= int(pr.portHigh); port++ { + rules = append(rules, portFilterTernaryRule{uint16(port), math.MaxUint16}) + } + } else { + return nil, ErrInvalidArgument("asComplexTernaryMatches", strategy) } return rules, nil @@ -192,7 +208,7 @@ func convertPortFiltersToTernary(src, dst portFilter) ([]portFilterTernaryCartes rules := make([]portFilterTernaryCartesianProduct, 0) if src.isRangeMatch() { - srcTernaryRules, err := src.asComplexTernaryMatches() + srcTernaryRules, err := src.asComplexTernaryMatches(Exact) if err != nil { return nil, err } @@ -208,7 +224,7 @@ func convertPortFiltersToTernary(src, dst portFilter) ([]portFilterTernaryCartes rules = append(rules, p) } } else if dst.isRangeMatch() { - dstTernaryRules, err := dst.asComplexTernaryMatches() + dstTernaryRules, err := dst.asComplexTernaryMatches(Exact) if err != nil { return nil, err } diff --git a/pfcpiface/parse-pdr_test.go b/pfcpiface/parse-pdr_test.go index ad3758c7a..ca3717bff 100644 --- a/pfcpiface/parse-pdr_test.go +++ b/pfcpiface/parse-pdr_test.go @@ -47,7 +47,13 @@ func Test_convertPortFiltersToTernary(t *testing.T) { }, { srcPort: 0x2, - srcMask: 0xfffe, + srcMask: 0xffff, + dstPort: 80, + dstMask: math.MaxUint16, + }, + { + srcPort: 0x3, + srcMask: 0xffff, dstPort: 80, dstMask: math.MaxUint16, }}, @@ -314,7 +320,7 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { portLow: tt.pr.portLow, portHigh: tt.pr.portHigh, } - got, err := pr.asComplexTernaryMatches() + got, err := pr.asComplexTernaryMatches(Exact) if (err != nil) != tt.wantErr { t.Errorf("asComplexTernaryMatches() error = %v, wantErr %v", err, tt.wantErr) return From 3e064cc1d0b80e8e1baf0799e084ce062ab9ed01 Mon Sep 17 00:00:00 2001 From: pudelkoM Date: Wed, 2 Feb 2022 16:03:31 -0800 Subject: [PATCH 09/18] Add exact match conversion strategy --- pfcpiface/parse-pdr.go | 21 +++++++++++++-------- pfcpiface/parse-pdr_test.go | 26 +++++++++++++++----------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/pfcpiface/parse-pdr.go b/pfcpiface/parse-pdr.go index 1160eeb93..0bd0fe6ff 100644 --- a/pfcpiface/parse-pdr.go +++ b/pfcpiface/parse-pdr.go @@ -134,7 +134,15 @@ func (pr portFilter) asComplexTernaryMatches(strategy RangeConversionStrategy) ( return rules, nil } - if strategy == Ternary { + if strategy == Exact { + if pr.Width() > 100 { + return nil, ErrInvalidArgumentWithReason("asComplexTernaryMatches", pr, + "port range too wide for exact match strategy") + } + for port := int(pr.portLow); port <= int(pr.portHigh); port++ { + rules = append(rules, portFilterTernaryRule{uint16(port), math.MaxUint16}) + } + } else if strategy == Ternary { // Adapted from https://stackoverflow.com/a/66959276 const limit = math.MaxUint16 maxPort := func(port, mask uint16) uint16 { @@ -171,10 +179,6 @@ func (pr portFilter) asComplexTernaryMatches(strategy RangeConversionStrategy) ( rules = append(rules, portFilterTernaryRule{uint16(port), mask}) port = uint32(maxPort(uint16(port), mask)) + 1 } - } else if strategy == Exact { - for port := int(pr.portLow); port <= int(pr.portHigh); port++ { - rules = append(rules, portFilterTernaryRule{uint16(port), math.MaxUint16}) - } } else { return nil, ErrInvalidArgument("asComplexTernaryMatches", strategy) } @@ -195,13 +199,14 @@ type portFilterTernaryCartesianProduct struct { dstPort, dstMask uint16 } -// Converts two port ranges into a list of ternary rules covering the same range. -func convertPortFiltersToTernary(src, dst portFilter) ([]portFilterTernaryCartesianProduct, error) { +// CreatePortFilterCartesianProduct converts two port ranges into a list of ternary +// rules covering the same range. +func CreatePortFilterCartesianProduct(src, dst portFilter) ([]portFilterTernaryCartesianProduct, error) { // A single range rule can result in multiple ternary ones. To cover the same range of packets, // we need to create the Cartesian product of src and dst rules. For now, we only allow one true // range match to keep the complexity in check. if src.isRangeMatch() && dst.isRangeMatch() { - return nil, ErrInvalidArgumentWithReason("convertPortFiltersToTernary", + return nil, ErrInvalidArgumentWithReason("CreatePortFilterCartesianProduct", src, "src and dst ports cannot both be a range match") } diff --git a/pfcpiface/parse-pdr_test.go b/pfcpiface/parse-pdr_test.go index ca3717bff..b58e07e16 100644 --- a/pfcpiface/parse-pdr_test.go +++ b/pfcpiface/parse-pdr_test.go @@ -7,7 +7,7 @@ import ( "testing" ) -func Test_convertPortFiltersToTernary(t *testing.T) { +func Test_CreatePortFilterCartesianProduct(t *testing.T) { type args struct { src portFilter dst portFilter @@ -66,13 +66,13 @@ func Test_convertPortFiltersToTernary(t *testing.T) { for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { - got, err := convertPortFiltersToTernary(tt.args.src, tt.args.dst) + got, err := CreatePortFilterCartesianProduct(tt.args.src, tt.args.dst) if (err != nil) != tt.wantErr { - t.Errorf("convertPortFiltersToTernary() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("CreatePortFilterCartesianProduct() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("convertPortFiltersToTernary() got = %v, want %v", got, tt.want) + t.Errorf("CreatePortFilterCartesianProduct() got = %v, want %v", got, tt.want) } }, ) @@ -227,10 +227,11 @@ func matchesTernary(value uint16, rules []portFilterTernaryRule) bool { func Test_portFilter_asComplexTernaryMatches(t *testing.T) { tests := []struct { - name string - pr portFilter - wantErr bool - want []portFilterTernaryRule + name string + pr portFilter + strategy RangeConversionStrategy + wantErr bool + want []portFilterTernaryRule }{ {name: "Exact match port range", pr: portFilter{ @@ -274,6 +275,7 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { portLow: 0x0100, // 256 portHigh: 0x01ff, // 511 }, + strategy: Ternary, //want: []portFilterTernaryRule{ // {port: 0x0100, mask: 0xff00}, //}, @@ -299,13 +301,15 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { portLow: 1, portHigh: 65534, }, - wantErr: false}, + strategy: Ternary, + wantErr: false}, {name: "low port filter", pr: portFilter{ portLow: 0, portHigh: 1023, }, - wantErr: false}, + strategy: Ternary, + wantErr: false}, {name: "some small app filter", pr: portFilter{ portLow: 8080, @@ -320,7 +324,7 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { portLow: tt.pr.portLow, portHigh: tt.pr.portHigh, } - got, err := pr.asComplexTernaryMatches(Exact) + got, err := pr.asComplexTernaryMatches(tt.strategy) if (err != nil) != tt.wantErr { t.Errorf("asComplexTernaryMatches() error = %v, wantErr %v", err, tt.wantErr) return From 7be1ae79792b097b2b8f7e8163ec44ef9f014f5c Mon Sep 17 00:00:00 2001 From: pudelkoM Date: Thu, 3 Feb 2022 10:32:49 -0800 Subject: [PATCH 10/18] Fix missing renames --- pfcpiface/bess.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pfcpiface/bess.go b/pfcpiface/bess.go index 997f0f330..563d4683b 100644 --- a/pfcpiface/bess.go +++ b/pfcpiface/bess.go @@ -712,12 +712,12 @@ func (b *bess) addPDR(ctx context.Context, done chan<- bool, p pdr) { } // Translate port ranges into ternary rule(s) and insert them one-by-one. - portRules, err := convertPortFiltersToTernary(p.appFilter.srcPortFilter, p.appFilter.dstPortFilter) + portRules, err := CreatePortFilterCartesianProduct(p.appFilter.srcPortFilter, p.appFilter.dstPortFilter) if err != nil { log.Errorln(err) return } - log.Warnln("PDR rules", portRules) + log.Tracef("PDR rules %+v", portRules) for _, r := range portRules { f := &pb.WildcardMatchCommandAddArg{ @@ -772,7 +772,7 @@ func (b *bess) delPDR(ctx context.Context, done chan<- bool, p pdr) { ) // Translate port ranges into ternary rule(s) and insert them one-by-one. - portRules, err := convertPortFiltersToTernary(p.appFilter.srcPortFilter, p.appFilter.dstPortFilter) + portRules, err := CreatePortFilterCartesianProduct(p.appFilter.srcPortFilter, p.appFilter.dstPortFilter) if err != nil { log.Errorln(err) return From 004a2a9178078727489e0723af4ca717744c7d31 Mon Sep 17 00:00:00 2001 From: pudelkoM Date: Thu, 3 Feb 2022 12:33:34 -0800 Subject: [PATCH 11/18] Use `portFilter` in application --- pfcpiface/p4rt_translator.go | 2 +- pfcpiface/up4.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pfcpiface/p4rt_translator.go b/pfcpiface/p4rt_translator.go index b96020f17..f88db9c0e 100644 --- a/pfcpiface/p4rt_translator.go +++ b/pfcpiface/p4rt_translator.go @@ -539,7 +539,7 @@ func (t *P4rtTranslator) BuildApplicationsTableEntry(pdr pdr, internalAppID uint } if !appPort.isWildcardMatch() { - if err := t.withRangeMatchField(entry, FieldAppL4Port, appPort, appPort); err != nil { + if err := t.withRangeMatchField(entry, FieldAppL4Port, appPort.portLow, appPort.portHigh); err != nil { return nil, err } } diff --git a/pfcpiface/up4.go b/pfcpiface/up4.go index 8c6a0ea7a..2d60a5f76 100644 --- a/pfcpiface/up4.go +++ b/pfcpiface/up4.go @@ -50,7 +50,7 @@ const ( type application struct { appIP uint32 - appL4Port uint16 + appL4Port portFilter appProto uint8 } @@ -573,7 +573,7 @@ func (up4 *UP4) allocateInternalApplicationID(app application) (uint8, error) { func (up4 *UP4) releaseInternalApplicationID(appFilter applicationFilter) { app := application{ appIP: appFilter.srcIP, - appL4Port: appFilter.srcPortFilter.asExactMatchUnchecked().port, + appL4Port: appFilter.srcPortFilter, appProto: appFilter.proto, } @@ -589,12 +589,12 @@ func (up4 *UP4) getOrAllocateInternalApplicationID(pdr pdr) (uint8, error) { if pdr.IsUplink() { app = application{ appIP: pdr.appFilter.dstIP, - appL4Port: pdr.appFilter.dstPortFilter.asExactMatchUnchecked().port, + appL4Port: pdr.appFilter.dstPortFilter, } } else if pdr.IsDownlink() { app = application{ appIP: pdr.appFilter.srcIP, - appL4Port: pdr.appFilter.srcPortFilter.asExactMatchUnchecked().port, + appL4Port: pdr.appFilter.srcPortFilter, } } From 5416561ba732c67a16f154439c8e0a2b899754c5 Mon Sep 17 00:00:00 2001 From: pudelkoM Date: Thu, 3 Feb 2022 17:18:04 -0800 Subject: [PATCH 12/18] Flip src and dst port in access PDRs --- pfcpiface/parse-pdr.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pfcpiface/parse-pdr.go b/pfcpiface/parse-pdr.go index 0bd0fe6ff..6d68e1ffb 100644 --- a/pfcpiface/parse-pdr.go +++ b/pfcpiface/parse-pdr.go @@ -498,8 +498,9 @@ func (p *pdr) parsePDI(seid uint64, pdiIEs []*ie.IE, appPFDs map[string]appPFD, p.appFilter.srcIPMask = ipMask2int(ipf.dst.IPNet.Mask) p.appFilter.dstIP = ip2int(ipf.src.IPNet.IP) p.appFilter.dstIPMask = ipMask2int(ipf.src.IPNet.Mask) - p.appFilter.dstPortFilter = ipf.dst.ports - p.appFilter.srcPortFilter = ipf.src.ports + // Ports are flipped for access PDRs + p.appFilter.dstPortFilter = ipf.src.ports + p.appFilter.srcPortFilter = ipf.dst.ports // FIXME: temporary workaround for SDF Filter, // remove once we meet spec compliance From 164226b50ed695396569c61ea7dd7efcfbc1cd17 Mon Sep 17 00:00:00 2001 From: pudelkoM Date: Thu, 3 Feb 2022 17:27:20 -0800 Subject: [PATCH 13/18] Lint and formatting --- pfcpiface/bess.go | 2 ++ pfcpiface/parse-pdr.go | 26 ++++++----------- pfcpiface/parse-pdr_test.go | 56 ++++++++++++++++--------------------- 3 files changed, 35 insertions(+), 49 deletions(-) diff --git a/pfcpiface/bess.go b/pfcpiface/bess.go index 563d4683b..fdce3ca05 100644 --- a/pfcpiface/bess.go +++ b/pfcpiface/bess.go @@ -717,6 +717,7 @@ func (b *bess) addPDR(ctx context.Context, done chan<- bool, p pdr) { log.Errorln(err) return } + log.Tracef("PDR rules %+v", portRules) for _, r := range portRules { @@ -807,6 +808,7 @@ func (b *bess) delPDR(ctx context.Context, done chan<- bool, p pdr) { log.Errorln("Error marshalling the rule", f, err) return } + b.processPDR(ctx, any, upfMsgTypeDel) } done <- true diff --git a/pfcpiface/parse-pdr.go b/pfcpiface/parse-pdr.go index 6d68e1ffb..a01db4aea 100644 --- a/pfcpiface/parse-pdr.go +++ b/pfcpiface/parse-pdr.go @@ -45,24 +45,13 @@ func newRangeMatchPortFilter(low, high uint16) portFilter { if low > high { return portFilter{} } + return portFilter{ portLow: low, portHigh: high, } } -// newTernaryMatchPortFilter returns a portFilter that matches on the given port and mask. Only -// trivial mask are supported. -func newTernaryMatchPortFilter(port, mask uint16) (portFilter, error) { - if mask == 0 { - return newWildcardPortFilter(), nil - } else if mask == math.MaxUint16 { - return newExactMatchPortFilter(port), nil - } else { - return portFilter{}, ErrInvalidArgument("newTernaryMatchPortFilter", mask) - } -} - func (pr portFilter) String() string { return fmt.Sprintf("{%v-%v}", pr.portLow, pr.portHigh) } @@ -96,10 +85,6 @@ func (pr portFilter) asExactMatchUnchecked() portFilterTernaryRule { return portFilterTernaryRule{port: pr.portLow, mask: math.MaxUint16} } -func (pr portFilter) asRangeMatchUnchecked() (uint16, uint16) { - return pr.portLow, pr.portHigh -} - // Return portFilter as a trivial, single value and mask, ternary match. Will fail if conversion is // not possible. func (pr portFilter) asTrivialTernaryMatch() (portFilterTernaryRule, error) { @@ -117,7 +102,6 @@ type RangeConversionStrategy int const ( Exact RangeConversionStrategy = iota Ternary - Hybrid ) // Returns portFilter as a list of ternary matches that cover the same range. @@ -129,6 +113,7 @@ func (pr portFilter) asComplexTernaryMatches(strategy RangeConversionStrategy) ( rules = append(rules, pr.asExactMatchUnchecked()) return rules, nil } + if pr.isWildcardMatch() { rules = append(rules, portFilterTernaryRule{0, 0}) return rules, nil @@ -139,6 +124,7 @@ func (pr portFilter) asComplexTernaryMatches(strategy RangeConversionStrategy) ( return nil, ErrInvalidArgumentWithReason("asComplexTernaryMatches", pr, "port range too wide for exact match strategy") } + for port := int(pr.portLow); port <= int(pr.portHigh); port++ { rules = append(rules, portFilterTernaryRule{uint16(port), math.MaxUint16}) } @@ -217,10 +203,12 @@ func CreatePortFilterCartesianProduct(src, dst portFilter) ([]portFilterTernaryC if err != nil { return nil, err } + dstTernary, err := dst.asTrivialTernaryMatch() if err != nil { return nil, err } + for _, r := range srcTernaryRules { p := portFilterTernaryCartesianProduct{ srcPort: r.port, srcMask: r.mask, @@ -233,10 +221,12 @@ func CreatePortFilterCartesianProduct(src, dst portFilter) ([]portFilterTernaryC if err != nil { return nil, err } + srcTernary, err := src.asTrivialTernaryMatch() if err != nil { return nil, err } + for _, r := range dstTernaryRules { p := portFilterTernaryCartesianProduct{ srcPort: srcTernary.port, srcMask: srcTernary.mask, @@ -250,10 +240,12 @@ func CreatePortFilterCartesianProduct(src, dst portFilter) ([]portFilterTernaryC if err != nil { return nil, err } + dstTernary, err := dst.asTrivialTernaryMatch() if err != nil { return nil, err } + p := portFilterTernaryCartesianProduct{ dstPort: dstTernary.port, dstMask: dstTernary.mask, srcPort: srcTernary.port, srcMask: srcTernary.mask, diff --git a/pfcpiface/parse-pdr_test.go b/pfcpiface/parse-pdr_test.go index b58e07e16..65c656e40 100644 --- a/pfcpiface/parse-pdr_test.go +++ b/pfcpiface/parse-pdr_test.go @@ -1,10 +1,11 @@ package main import ( - "github.com/stretchr/testify/assert" "math" "reflect" "testing" + + "github.com/stretchr/testify/assert" ) func Test_CreatePortFilterCartesianProduct(t *testing.T) { @@ -12,6 +13,7 @@ func Test_CreatePortFilterCartesianProduct(t *testing.T) { src portFilter dst portFilter } + tests := []struct { name string args args @@ -63,6 +65,7 @@ func Test_CreatePortFilterCartesianProduct(t *testing.T) { want: nil, wantErr: true}, } + for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { @@ -104,23 +107,20 @@ func Test_newWildcardPortFilter(t *testing.T) { } func Test_portFilter_String(t *testing.T) { - type fields struct { - PortLow uint16 - PortHigh uint16 - } tests := []struct { name string - fields fields + fields portFilter want string }{ // TODO: Add test cases. } + for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { pr := portFilter{ - portLow: tt.fields.PortLow, - portHigh: tt.fields.PortHigh, + portLow: tt.fields.portLow, + portHigh: tt.fields.portHigh, } if got := pr.String(); got != tt.want { t.Errorf("String() = %v, want %v", got, tt.want) @@ -131,23 +131,20 @@ func Test_portFilter_String(t *testing.T) { } func Test_portFilter_isExactMatch(t *testing.T) { - type fields struct { - PortLow uint16 - PortHigh uint16 - } tests := []struct { name string - fields fields + fields portFilter want bool }{ // TODO: Add test cases. } + for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { pr := portFilter{ - portLow: tt.fields.PortLow, - portHigh: tt.fields.PortHigh, + portLow: tt.fields.portLow, + portHigh: tt.fields.portHigh, } if got := pr.isExactMatch(); got != tt.want { t.Errorf("isExactMatch() = %v, want %v", got, tt.want) @@ -158,23 +155,20 @@ func Test_portFilter_isExactMatch(t *testing.T) { } func Test_portFilter_isRangeMatch(t *testing.T) { - type fields struct { - PortLow uint16 - PortHigh uint16 - } tests := []struct { name string - fields fields + fields portFilter want bool }{ // TODO: Add test cases. } + for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { pr := portFilter{ - portLow: tt.fields.PortLow, - portHigh: tt.fields.PortHigh, + portLow: tt.fields.portLow, + portHigh: tt.fields.portHigh, } if got := pr.isRangeMatch(); got != tt.want { t.Errorf("isRangeMatch() = %v, want %v", got, tt.want) @@ -185,27 +179,24 @@ func Test_portFilter_isRangeMatch(t *testing.T) { } func Test_portFilter_isWildcardMatch(t *testing.T) { - type fields struct { - PortLow uint16 - PortHigh uint16 - } tests := []struct { name string - fields fields + fields portFilter want bool }{ // TODO: Add test cases. - {name: "foo", fields: fields{ - PortLow: 0, - PortHigh: 0, + {name: "foo", fields: portFilter{ + portLow: 0, + portHigh: 0, }, want: true}, } + for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { pr := portFilter{ - portLow: tt.fields.PortLow, - portHigh: tt.fields.PortHigh, + portLow: tt.fields.portLow, + portHigh: tt.fields.portHigh, } if got := pr.isWildcardMatch(); got != tt.want { t.Errorf("isWildcardMatch() = %v, want %v", got, tt.want) @@ -222,6 +213,7 @@ func matchesTernary(value uint16, rules []portFilterTernaryRule) bool { return true } } + return false } From 82362d966bb0e1b71e02cf586d454ab1fbac0fc0 Mon Sep 17 00:00:00 2001 From: pudelkoM Date: Fri, 4 Feb 2022 11:34:15 -0800 Subject: [PATCH 14/18] Rename `portFilter` to `portRange` --- pfcpiface/p4rt_translator.go | 4 +- pfcpiface/parse-pdr.go | 90 ++++++++++---------- pfcpiface/parse-pdr_test.go | 156 +++++++++++++++-------------------- pfcpiface/parse-sdf.go | 2 +- pfcpiface/up4.go | 2 +- 5 files changed, 117 insertions(+), 137 deletions(-) diff --git a/pfcpiface/p4rt_translator.go b/pfcpiface/p4rt_translator.go index f88db9c0e..d108285e3 100644 --- a/pfcpiface/p4rt_translator.go +++ b/pfcpiface/p4rt_translator.go @@ -518,7 +518,7 @@ func (t *P4rtTranslator) BuildApplicationsTableEntry(pdr pdr, internalAppID uint var ( appIP, appIPMask uint32 = 0, 0 - appPort portFilter + appPort portRange ) if pdr.srcIface == access { @@ -539,7 +539,7 @@ func (t *P4rtTranslator) BuildApplicationsTableEntry(pdr pdr, internalAppID uint } if !appPort.isWildcardMatch() { - if err := t.withRangeMatchField(entry, FieldAppL4Port, appPort.portLow, appPort.portHigh); err != nil { + if err := t.withRangeMatchField(entry, FieldAppL4Port, appPort.low, appPort.high); err != nil { return nil, err } } diff --git a/pfcpiface/parse-pdr.go b/pfcpiface/parse-pdr.go index cc953397f..ef64f552c 100644 --- a/pfcpiface/parse-pdr.go +++ b/pfcpiface/parse-pdr.go @@ -14,80 +14,80 @@ import ( "github.com/wmnsk/go-pfcp/ie" ) -// portFilter encapsulates a L4 port range as seen in PDRs. A zero value portFilter represents +// portRange encapsulates a L4 port range as seen in PDRs. A zero value portRange represents // a wildcard match, but use of the dedicated new*PortFilter() functions is encouraged. -type portFilter struct { - portLow uint16 - portHigh uint16 +type portRange struct { + low uint16 + high uint16 } -// newWildcardPortFilter returns a portFilter that matches on every possible port, i.e., implements +// newWildcardPortFilter returns a portRange that matches on every possible port, i.e., implements // no filtering. -func newWildcardPortFilter() portFilter { - return portFilter{ - portLow: 0, - portHigh: math.MaxUint16, +func newWildcardPortFilter() portRange { + return portRange{ + low: 0, + high: math.MaxUint16, } } -// newExactMatchPortFilter returns a portFilter that matches on exactly the given port. -func newExactMatchPortFilter(port uint16) portFilter { - return portFilter{ - portLow: port, - portHigh: port, +// newExactMatchPortFilter returns a portRange that matches on exactly the given port. +func newExactMatchPortFilter(port uint16) portRange { + return portRange{ + low: port, + high: port, } } -// newRangeMatchPortFilter returns a portFilter that matches on the given range [low, high]. +// newRangeMatchPortFilter returns a portRange that matches on the given range [low, high]. // low must be smaller than high. Creating exact and wildcard matches with this function is // possible, but use of the dedicated functions is encouraged. -func newRangeMatchPortFilter(low, high uint16) portFilter { +func newRangeMatchPortFilter(low, high uint16) portRange { if low > high { - return portFilter{} + return portRange{} } - return portFilter{ - portLow: low, - portHigh: high, + return portRange{ + low: low, + high: high, } } -func (pr portFilter) String() string { - return fmt.Sprintf("{%v-%v}", pr.portLow, pr.portHigh) +func (pr portRange) String() string { + return fmt.Sprintf("{%v-%v}", pr.low, pr.high) } -// Width returns the number of ports covered by this portFilter. -func (pr portFilter) Width() uint16 { +// Width returns the number of ports covered by this portRange. +func (pr portRange) Width() uint16 { // Need to handle the zero value. if pr.isWildcardMatch() { return math.MaxUint16 } else { - return pr.portHigh - pr.portLow + 1 + return pr.high - pr.low + 1 } } -func (pr portFilter) isWildcardMatch() bool { - return pr.portLow == 0 && pr.portHigh == math.MaxUint16 || - pr.portLow == 0 && pr.portHigh == 0 +func (pr portRange) isWildcardMatch() bool { + return pr.low == 0 && pr.high == math.MaxUint16 || + pr.low == 0 && pr.high == 0 } -func (pr portFilter) isExactMatch() bool { - return pr.portLow == pr.portHigh && pr.portHigh != 0 +func (pr portRange) isExactMatch() bool { + return pr.low == pr.high && pr.high != 0 } -func (pr portFilter) isRangeMatch() bool { +func (pr portRange) isRangeMatch() bool { return !pr.isExactMatch() && !pr.isWildcardMatch() } -// Returns portFilter as an exact match, without checking if it is one. isExactMatch() must be true +// Returns portRange as an exact match, without checking if it is one. isExactMatch() must be true // before calling asExactMatchUnchecked. -func (pr portFilter) asExactMatchUnchecked() portFilterTernaryRule { - return portFilterTernaryRule{port: pr.portLow, mask: math.MaxUint16} +func (pr portRange) asExactMatchUnchecked() portFilterTernaryRule { + return portFilterTernaryRule{port: pr.low, mask: math.MaxUint16} } -// Return portFilter as a trivial, single value and mask, ternary match. Will fail if conversion is +// Return portRange as a trivial, single value and mask, ternary match. Will fail if conversion is // not possible. -func (pr portFilter) asTrivialTernaryMatch() (portFilterTernaryRule, error) { +func (pr portRange) asTrivialTernaryMatch() (portFilterTernaryRule, error) { if pr.isWildcardMatch() { return portFilterTernaryRule{0, 0}, nil } else if pr.isExactMatch() { @@ -104,8 +104,8 @@ const ( Ternary ) -// Returns portFilter as a list of ternary matches that cover the same range. -func (pr portFilter) asComplexTernaryMatches(strategy RangeConversionStrategy) ([]portFilterTernaryRule, error) { +// Returns portRange as a list of ternary matches that cover the same range. +func (pr portRange) asComplexTernaryMatches(strategy RangeConversionStrategy) ([]portFilterTernaryRule, error) { rules := make([]portFilterTernaryRule, 0) // Fast path for exact and wildcard matches which are trivial. @@ -125,7 +125,7 @@ func (pr portFilter) asComplexTernaryMatches(strategy RangeConversionStrategy) ( "port range too wide for exact match strategy") } - for port := int(pr.portLow); port <= int(pr.portHigh); port++ { + for port := int(pr.low); port <= int(pr.high); port++ { rules = append(rules, portFilterTernaryRule{uint16(port), math.MaxUint16}) } } else if strategy == Ternary { @@ -159,9 +159,9 @@ func (pr portFilter) asComplexTernaryMatches(strategy RangeConversionStrategy) ( return mask } - port := uint32(pr.portLow) // Promote to higher bit width for greater-equals check. - for port <= uint32(pr.portHigh) { - mask := portMask(uint16(port), pr.portHigh) + port := uint32(pr.low) // Promote to higher bit width for greater-equals check. + for port <= uint32(pr.high) { + mask := portMask(uint16(port), pr.high) rules = append(rules, portFilterTernaryRule{uint16(port), mask}) port = uint32(maxPort(uint16(port), mask)) + 1 } @@ -187,7 +187,7 @@ type portFilterTernaryCartesianProduct struct { // CreatePortFilterCartesianProduct converts two port ranges into a list of ternary // rules covering the same range. -func CreatePortFilterCartesianProduct(src, dst portFilter) ([]portFilterTernaryCartesianProduct, error) { +func CreatePortFilterCartesianProduct(src, dst portRange) ([]portFilterTernaryCartesianProduct, error) { // A single range rule can result in multiple ternary ones. To cover the same range of packets, // we need to create the Cartesian product of src and dst rules. For now, we only allow one true // range match to keep the complexity in check. @@ -259,8 +259,8 @@ func CreatePortFilterCartesianProduct(src, dst portFilter) ([]portFilterTernaryC type applicationFilter struct { srcIP uint32 dstIP uint32 - srcPortFilter portFilter - dstPortFilter portFilter + srcPortFilter portRange + dstPortFilter portRange proto uint8 srcIPMask uint32 diff --git a/pfcpiface/parse-pdr_test.go b/pfcpiface/parse-pdr_test.go index 65c656e40..b188104e0 100644 --- a/pfcpiface/parse-pdr_test.go +++ b/pfcpiface/parse-pdr_test.go @@ -10,8 +10,8 @@ import ( func Test_CreatePortFilterCartesianProduct(t *testing.T) { type args struct { - src portFilter - dst portFilter + src portRange + dst portRange } tests := []struct { @@ -84,14 +84,14 @@ func Test_CreatePortFilterCartesianProduct(t *testing.T) { func Test_defaultPortFilter(t *testing.T) { t.Run("default constructed is wildcard", func(t *testing.T) { - assert.True(t, portFilter{}.isWildcardMatch(), "default portFilter is wildcard") + assert.True(t, portRange{}.isWildcardMatch(), "default portRange is wildcard") }) } func Test_newWildcardPortFilter(t *testing.T) { tests := []struct { name string - want portFilter + want portRange }{ // TODO: Add test cases. } @@ -108,9 +108,9 @@ func Test_newWildcardPortFilter(t *testing.T) { func Test_portFilter_String(t *testing.T) { tests := []struct { - name string - fields portFilter - want string + name string + pr portRange + want string }{ // TODO: Add test cases. } @@ -118,11 +118,7 @@ func Test_portFilter_String(t *testing.T) { for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { - pr := portFilter{ - portLow: tt.fields.portLow, - portHigh: tt.fields.portHigh, - } - if got := pr.String(); got != tt.want { + if got := tt.pr.String(); got != tt.want { t.Errorf("String() = %v, want %v", got, tt.want) } }, @@ -132,9 +128,9 @@ func Test_portFilter_String(t *testing.T) { func Test_portFilter_isExactMatch(t *testing.T) { tests := []struct { - name string - fields portFilter - want bool + name string + pr portRange + want bool }{ // TODO: Add test cases. } @@ -142,11 +138,7 @@ func Test_portFilter_isExactMatch(t *testing.T) { for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { - pr := portFilter{ - portLow: tt.fields.portLow, - portHigh: tt.fields.portHigh, - } - if got := pr.isExactMatch(); got != tt.want { + if got := tt.pr.isExactMatch(); got != tt.want { t.Errorf("isExactMatch() = %v, want %v", got, tt.want) } }, @@ -156,9 +148,9 @@ func Test_portFilter_isExactMatch(t *testing.T) { func Test_portFilter_isRangeMatch(t *testing.T) { tests := []struct { - name string - fields portFilter - want bool + name string + pr portRange + want bool }{ // TODO: Add test cases. } @@ -166,11 +158,7 @@ func Test_portFilter_isRangeMatch(t *testing.T) { for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { - pr := portFilter{ - portLow: tt.fields.portLow, - portHigh: tt.fields.portHigh, - } - if got := pr.isRangeMatch(); got != tt.want { + if got := tt.pr.isRangeMatch(); got != tt.want { t.Errorf("isRangeMatch() = %v, want %v", got, tt.want) } }, @@ -180,25 +168,21 @@ func Test_portFilter_isRangeMatch(t *testing.T) { func Test_portFilter_isWildcardMatch(t *testing.T) { tests := []struct { - name string - fields portFilter - want bool + name string + pr portRange + want bool }{ // TODO: Add test cases. - {name: "foo", fields: portFilter{ - portLow: 0, - portHigh: 0, + {name: "foo", pr: portRange{ + low: 0, + high: 0, }, want: true}, } for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { - pr := portFilter{ - portLow: tt.fields.portLow, - portHigh: tt.fields.portHigh, - } - if got := pr.isWildcardMatch(); got != tt.want { + if got := tt.pr.isWildcardMatch(); got != tt.want { t.Errorf("isWildcardMatch() = %v, want %v", got, tt.want) } }, @@ -220,42 +204,42 @@ func matchesTernary(value uint16, rules []portFilterTernaryRule) bool { func Test_portFilter_asComplexTernaryMatches(t *testing.T) { tests := []struct { name string - pr portFilter + pr portRange strategy RangeConversionStrategy wantErr bool want []portFilterTernaryRule }{ {name: "Exact match port range", - pr: portFilter{ - portLow: 8888, - portHigh: 8888, + pr: portRange{ + low: 8888, + high: 8888, }, want: []portFilterTernaryRule{ {port: 8888, mask: 0xffff}, }, wantErr: false}, {name: "wildcard port range", - pr: portFilter{ - portLow: 0, - portHigh: math.MaxUint16, + pr: portRange{ + low: 0, + high: math.MaxUint16, }, want: []portFilterTernaryRule{ {port: 0, mask: 0}, }, wantErr: false}, {name: "Simplest port range", - pr: portFilter{ - portLow: 0b0, // 0 - portHigh: 0b1, // 1 + pr: portRange{ + low: 0b0, // 0 + high: 0b1, // 1 }, //want: []portFilterTernaryRule{ // {port: 0b0, mask: 0xfffe}, //}, wantErr: false}, {name: "Simplest port range2", - pr: portFilter{ - portLow: 0b01, // 1 - portHigh: 0b10, // 2 + pr: portRange{ + low: 0b01, // 1 + high: 0b10, // 2 }, //want: []portFilterTernaryRule{ // {port: 0b01, mask: 0xffff}, @@ -263,9 +247,9 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { //}, wantErr: false}, {name: "Trivial ternary port range", - pr: portFilter{ - portLow: 0x0100, // 256 - portHigh: 0x01ff, // 511 + pr: portRange{ + low: 0x0100, // 256 + high: 0x01ff, // 511 }, strategy: Ternary, //want: []portFilterTernaryRule{ @@ -273,9 +257,9 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { //}, wantErr: false}, {name: "one to three range", - pr: portFilter{ - portLow: 0b01, // 1 - portHigh: 0b11, // 3 + pr: portRange{ + low: 0b01, // 1 + high: 0b11, // 3 }, //want: []portFilterTernaryRule{ // {port: 0b01, mask: 0xffff}, @@ -283,40 +267,36 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { //}, wantErr: false}, {name: "True port range", - pr: portFilter{ - portLow: 0b00010, // 2 - portHigh: 0b11101, // 29 + pr: portRange{ + low: 0b00010, // 2 + high: 0b11101, // 29 }, wantErr: false}, {name: "Worst case port range", - pr: portFilter{ - portLow: 1, - portHigh: 65534, + pr: portRange{ + low: 1, + high: 65534, }, strategy: Ternary, wantErr: false}, {name: "low port filter", - pr: portFilter{ - portLow: 0, - portHigh: 1023, + pr: portRange{ + low: 0, + high: 1023, }, strategy: Ternary, wantErr: false}, {name: "some small app filter", - pr: portFilter{ - portLow: 8080, - portHigh: 8084, + pr: portRange{ + low: 8080, + high: 8084, }, wantErr: false}, } for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { - pr := portFilter{ - portLow: tt.pr.portLow, - portHigh: tt.pr.portHigh, - } - got, err := pr.asComplexTernaryMatches(tt.strategy) + got, err := tt.pr.asComplexTernaryMatches(tt.strategy) if (err != nil) != tt.wantErr { t.Errorf("asComplexTernaryMatches() error = %v, wantErr %v", err, tt.wantErr) return @@ -326,7 +306,7 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { } // Do exhaustive test over entire value range. for port := 0; port <= math.MaxUint16; port++ { - expectMatch := port >= int(tt.pr.portLow) && port <= int(tt.pr.portHigh) + expectMatch := port >= int(tt.pr.low) && port <= int(tt.pr.high) if matchesTernary(uint16(port), got) != expectMatch { mod := " " if !expectMatch { @@ -343,22 +323,22 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { func Test_portFilter_asTrivialTernaryMatch(t *testing.T) { tests := []struct { name string - pr portFilter + pr portRange wantPort uint16 wantMask uint16 wantErr bool }{ - {name: "Wildcard range", pr: portFilter{ - portLow: 0, - portHigh: 0, + {name: "Wildcard range", pr: portRange{ + low: 0, + high: 0, }, wantPort: 0, wantMask: 0, wantErr: false}, - {name: "Exact match range", pr: portFilter{ - portLow: 100, - portHigh: 100, + {name: "Exact match range", pr: portRange{ + low: 100, + high: 100, }, wantPort: 100, wantMask: 0xffff, wantErr: false}, - {name: "True range match fail", pr: portFilter{ - portLow: 100, - portHigh: 200, + {name: "True range match fail", pr: portRange{ + low: 100, + high: 200, }, wantPort: 0, wantMask: 0, wantErr: true}, // TODO: Add test cases. } @@ -385,11 +365,11 @@ func Test_portFilter_asTrivialTernaryMatch(t *testing.T) { func Test_portFilter_Width(t *testing.T) { tests := []struct { name string - pr portFilter + pr portRange want uint16 }{ {name: "wildcard", pr: newWildcardPortFilter(), want: math.MaxUint16}, - {name: "zero value", pr: portFilter{}, want: math.MaxUint16}, + {name: "zero value", pr: portRange{}, want: math.MaxUint16}, {name: "exact match", pr: newExactMatchPortFilter(100), want: 1}, {name: "range match", pr: newRangeMatchPortFilter(10, 12), want: 3}, {name: "range single match", pr: newRangeMatchPortFilter(1000, 1000), want: 1}, diff --git a/pfcpiface/parse-sdf.go b/pfcpiface/parse-sdf.go index 05649ba78..31d0cd311 100644 --- a/pfcpiface/parse-sdf.go +++ b/pfcpiface/parse-sdf.go @@ -22,7 +22,7 @@ var errBadFilterDesc = errors.New("unsupported Filter Description format") type endpoint struct { IPNet *net.IPNet - ports portFilter + ports portRange } func (ep *endpoint) parseNet(ipnet string) error { diff --git a/pfcpiface/up4.go b/pfcpiface/up4.go index b5927e586..064162ca7 100644 --- a/pfcpiface/up4.go +++ b/pfcpiface/up4.go @@ -50,7 +50,7 @@ const ( type application struct { appIP uint32 - appL4Port portFilter + appL4Port portRange appProto uint8 } From 625de2e959a73508538c73b964a0c0702bc02814 Mon Sep 17 00:00:00 2001 From: pudelkoM Date: Fri, 4 Feb 2022 11:39:15 -0800 Subject: [PATCH 15/18] Fix missed renames --- pfcpiface/parse-pdr.go | 36 +++++++++++++++++------------------ pfcpiface/parse-pdr_test.go | 38 ++++++++++++++++++------------------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/pfcpiface/parse-pdr.go b/pfcpiface/parse-pdr.go index ef64f552c..2ba55f7e7 100644 --- a/pfcpiface/parse-pdr.go +++ b/pfcpiface/parse-pdr.go @@ -81,20 +81,20 @@ func (pr portRange) isRangeMatch() bool { // Returns portRange as an exact match, without checking if it is one. isExactMatch() must be true // before calling asExactMatchUnchecked. -func (pr portRange) asExactMatchUnchecked() portFilterTernaryRule { - return portFilterTernaryRule{port: pr.low, mask: math.MaxUint16} +func (pr portRange) asExactMatchUnchecked() portRangeTernaryRule { + return portRangeTernaryRule{port: pr.low, mask: math.MaxUint16} } // Return portRange as a trivial, single value and mask, ternary match. Will fail if conversion is // not possible. -func (pr portRange) asTrivialTernaryMatch() (portFilterTernaryRule, error) { +func (pr portRange) asTrivialTernaryMatch() (portRangeTernaryRule, error) { if pr.isWildcardMatch() { - return portFilterTernaryRule{0, 0}, nil + return portRangeTernaryRule{0, 0}, nil } else if pr.isExactMatch() { return pr.asExactMatchUnchecked(), nil } - return portFilterTernaryRule{}, ErrInvalidArgumentWithReason("asTrivialTernaryMatch", pr, "not trivially convertible") + return portRangeTernaryRule{}, ErrInvalidArgumentWithReason("asTrivialTernaryMatch", pr, "not trivially convertible") } type RangeConversionStrategy int @@ -105,8 +105,8 @@ const ( ) // Returns portRange as a list of ternary matches that cover the same range. -func (pr portRange) asComplexTernaryMatches(strategy RangeConversionStrategy) ([]portFilterTernaryRule, error) { - rules := make([]portFilterTernaryRule, 0) +func (pr portRange) asComplexTernaryMatches(strategy RangeConversionStrategy) ([]portRangeTernaryRule, error) { + rules := make([]portRangeTernaryRule, 0) // Fast path for exact and wildcard matches which are trivial. if pr.isExactMatch() { @@ -115,7 +115,7 @@ func (pr portRange) asComplexTernaryMatches(strategy RangeConversionStrategy) ([ } if pr.isWildcardMatch() { - rules = append(rules, portFilterTernaryRule{0, 0}) + rules = append(rules, portRangeTernaryRule{0, 0}) return rules, nil } @@ -126,7 +126,7 @@ func (pr portRange) asComplexTernaryMatches(strategy RangeConversionStrategy) ([ } for port := int(pr.low); port <= int(pr.high); port++ { - rules = append(rules, portFilterTernaryRule{uint16(port), math.MaxUint16}) + rules = append(rules, portRangeTernaryRule{uint16(port), math.MaxUint16}) } } else if strategy == Ternary { // Adapted from https://stackoverflow.com/a/66959276 @@ -162,7 +162,7 @@ func (pr portRange) asComplexTernaryMatches(strategy RangeConversionStrategy) ([ port := uint32(pr.low) // Promote to higher bit width for greater-equals check. for port <= uint32(pr.high) { mask := portMask(uint16(port), pr.high) - rules = append(rules, portFilterTernaryRule{uint16(port), mask}) + rules = append(rules, portRangeTernaryRule{uint16(port), mask}) port = uint32(maxPort(uint16(port), mask)) + 1 } } else { @@ -172,22 +172,22 @@ func (pr portRange) asComplexTernaryMatches(strategy RangeConversionStrategy) ([ return rules, nil } -type portFilterTernaryRule struct { +type portRangeTernaryRule struct { port, mask uint16 } -func (pf portFilterTernaryRule) String() string { +func (pf portRangeTernaryRule) String() string { return fmt.Sprintf("{0b%b & 0b%b}", pf.port, pf.mask) } -type portFilterTernaryCartesianProduct struct { +type portRangeTernaryCartesianProduct struct { srcPort, srcMask uint16 dstPort, dstMask uint16 } // CreatePortFilterCartesianProduct converts two port ranges into a list of ternary // rules covering the same range. -func CreatePortFilterCartesianProduct(src, dst portRange) ([]portFilterTernaryCartesianProduct, error) { +func CreatePortFilterCartesianProduct(src, dst portRange) ([]portRangeTernaryCartesianProduct, error) { // A single range rule can result in multiple ternary ones. To cover the same range of packets, // we need to create the Cartesian product of src and dst rules. For now, we only allow one true // range match to keep the complexity in check. @@ -196,7 +196,7 @@ func CreatePortFilterCartesianProduct(src, dst portRange) ([]portFilterTernaryCa src, "src and dst ports cannot both be a range match") } - rules := make([]portFilterTernaryCartesianProduct, 0) + rules := make([]portRangeTernaryCartesianProduct, 0) if src.isRangeMatch() { srcTernaryRules, err := src.asComplexTernaryMatches(Exact) @@ -210,7 +210,7 @@ func CreatePortFilterCartesianProduct(src, dst portRange) ([]portFilterTernaryCa } for _, r := range srcTernaryRules { - p := portFilterTernaryCartesianProduct{ + p := portRangeTernaryCartesianProduct{ srcPort: r.port, srcMask: r.mask, dstPort: dstTernary.port, dstMask: dstTernary.mask, } @@ -228,7 +228,7 @@ func CreatePortFilterCartesianProduct(src, dst portRange) ([]portFilterTernaryCa } for _, r := range dstTernaryRules { - p := portFilterTernaryCartesianProduct{ + p := portRangeTernaryCartesianProduct{ srcPort: srcTernary.port, srcMask: srcTernary.mask, dstPort: r.port, dstMask: r.mask, } @@ -246,7 +246,7 @@ func CreatePortFilterCartesianProduct(src, dst portRange) ([]portFilterTernaryCa return nil, err } - p := portFilterTernaryCartesianProduct{ + p := portRangeTernaryCartesianProduct{ dstPort: dstTernary.port, dstMask: dstTernary.mask, srcPort: srcTernary.port, srcMask: srcTernary.mask, } diff --git a/pfcpiface/parse-pdr_test.go b/pfcpiface/parse-pdr_test.go index b188104e0..fd550c5b2 100644 --- a/pfcpiface/parse-pdr_test.go +++ b/pfcpiface/parse-pdr_test.go @@ -17,12 +17,12 @@ func Test_CreatePortFilterCartesianProduct(t *testing.T) { tests := []struct { name string args args - want []portFilterTernaryCartesianProduct + want []portRangeTernaryCartesianProduct wantErr bool }{ {name: "exact ranges", args: args{src: newExactMatchPortFilter(5000), dst: newExactMatchPortFilter(80)}, - want: []portFilterTernaryCartesianProduct{{ + want: []portRangeTernaryCartesianProduct{{ srcPort: 5000, srcMask: math.MaxUint16, dstPort: 80, @@ -31,7 +31,7 @@ func Test_CreatePortFilterCartesianProduct(t *testing.T) { wantErr: false}, {name: "wildcard dst range", args: args{src: newExactMatchPortFilter(10), dst: newWildcardPortFilter()}, - want: []portFilterTernaryCartesianProduct{{ + want: []portRangeTernaryCartesianProduct{{ srcPort: 10, srcMask: math.MaxUint16, dstPort: 0, @@ -40,7 +40,7 @@ func Test_CreatePortFilterCartesianProduct(t *testing.T) { wantErr: false}, {name: "true range src range", args: args{src: newRangeMatchPortFilter(1, 3), dst: newExactMatchPortFilter(80)}, - want: []portFilterTernaryCartesianProduct{ + want: []portRangeTernaryCartesianProduct{ { srcPort: 0x1, srcMask: 0xffff, @@ -106,7 +106,7 @@ func Test_newWildcardPortFilter(t *testing.T) { } } -func Test_portFilter_String(t *testing.T) { +func Test_portRange_String(t *testing.T) { tests := []struct { name string pr portRange @@ -126,7 +126,7 @@ func Test_portFilter_String(t *testing.T) { } } -func Test_portFilter_isExactMatch(t *testing.T) { +func Test_portRange_isExactMatch(t *testing.T) { tests := []struct { name string pr portRange @@ -146,7 +146,7 @@ func Test_portFilter_isExactMatch(t *testing.T) { } } -func Test_portFilter_isRangeMatch(t *testing.T) { +func Test_portRange_isRangeMatch(t *testing.T) { tests := []struct { name string pr portRange @@ -166,7 +166,7 @@ func Test_portFilter_isRangeMatch(t *testing.T) { } } -func Test_portFilter_isWildcardMatch(t *testing.T) { +func Test_portRange_isWildcardMatch(t *testing.T) { tests := []struct { name string pr portRange @@ -191,7 +191,7 @@ func Test_portFilter_isWildcardMatch(t *testing.T) { } // Perform a ternary match of value against rules. -func matchesTernary(value uint16, rules []portFilterTernaryRule) bool { +func matchesTernary(value uint16, rules []portRangeTernaryRule) bool { for _, r := range rules { if (value & r.mask) == r.port { return true @@ -201,20 +201,20 @@ func matchesTernary(value uint16, rules []portFilterTernaryRule) bool { return false } -func Test_portFilter_asComplexTernaryMatches(t *testing.T) { +func Test_portRange_asComplexTernaryMatches(t *testing.T) { tests := []struct { name string pr portRange strategy RangeConversionStrategy wantErr bool - want []portFilterTernaryRule + want []portRangeTernaryRule }{ {name: "Exact match port range", pr: portRange{ low: 8888, high: 8888, }, - want: []portFilterTernaryRule{ + want: []portRangeTernaryRule{ {port: 8888, mask: 0xffff}, }, wantErr: false}, @@ -223,7 +223,7 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { low: 0, high: math.MaxUint16, }, - want: []portFilterTernaryRule{ + want: []portRangeTernaryRule{ {port: 0, mask: 0}, }, wantErr: false}, @@ -232,7 +232,7 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { low: 0b0, // 0 high: 0b1, // 1 }, - //want: []portFilterTernaryRule{ + //want: []portRangeTernaryRule{ // {port: 0b0, mask: 0xfffe}, //}, wantErr: false}, @@ -241,7 +241,7 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { low: 0b01, // 1 high: 0b10, // 2 }, - //want: []portFilterTernaryRule{ + //want: []portRangeTernaryRule{ // {port: 0b01, mask: 0xffff}, // {port: 0b10, mask: 0xffff}, //}, @@ -252,7 +252,7 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { high: 0x01ff, // 511 }, strategy: Ternary, - //want: []portFilterTernaryRule{ + //want: []portRangeTernaryRule{ // {port: 0x0100, mask: 0xff00}, //}, wantErr: false}, @@ -261,7 +261,7 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { low: 0b01, // 1 high: 0b11, // 3 }, - //want: []portFilterTernaryRule{ + //want: []portRangeTernaryRule{ // {port: 0b01, mask: 0xffff}, // {port: 0b10, mask: 0xfffe}, //}, @@ -320,7 +320,7 @@ func Test_portFilter_asComplexTernaryMatches(t *testing.T) { } } -func Test_portFilter_asTrivialTernaryMatch(t *testing.T) { +func Test_portRange_asTrivialTernaryMatch(t *testing.T) { tests := []struct { name string pr portRange @@ -362,7 +362,7 @@ func Test_portFilter_asTrivialTernaryMatch(t *testing.T) { } } -func Test_portFilter_Width(t *testing.T) { +func Test_portRange_Width(t *testing.T) { tests := []struct { name string pr portRange From f9bd979bea04291c8f096293490d2a640592b7c0 Mon Sep 17 00:00:00 2001 From: pudelkoM Date: Fri, 4 Feb 2022 11:58:32 -0800 Subject: [PATCH 16/18] More renames --- pfcpiface/bess.go | 4 +-- pfcpiface/p4rt_translator.go | 4 +-- pfcpiface/parse-pdr.go | 56 ++++++++++++++++++------------------ pfcpiface/parse-pdr_test.go | 32 ++++++++++----------- pfcpiface/parse-sdf.go | 6 ++-- pfcpiface/up4.go | 6 ++-- 6 files changed, 54 insertions(+), 54 deletions(-) diff --git a/pfcpiface/bess.go b/pfcpiface/bess.go index fdce3ca05..80c8ccda0 100644 --- a/pfcpiface/bess.go +++ b/pfcpiface/bess.go @@ -712,7 +712,7 @@ func (b *bess) addPDR(ctx context.Context, done chan<- bool, p pdr) { } // Translate port ranges into ternary rule(s) and insert them one-by-one. - portRules, err := CreatePortFilterCartesianProduct(p.appFilter.srcPortFilter, p.appFilter.dstPortFilter) + portRules, err := CreatePortRangeCartesianProduct(p.appFilter.srcPortRange, p.appFilter.dstPortRange) if err != nil { log.Errorln(err) return @@ -773,7 +773,7 @@ func (b *bess) delPDR(ctx context.Context, done chan<- bool, p pdr) { ) // Translate port ranges into ternary rule(s) and insert them one-by-one. - portRules, err := CreatePortFilterCartesianProduct(p.appFilter.srcPortFilter, p.appFilter.dstPortFilter) + portRules, err := CreatePortRangeCartesianProduct(p.appFilter.srcPortRange, p.appFilter.dstPortRange) if err != nil { log.Errorln(err) return diff --git a/pfcpiface/p4rt_translator.go b/pfcpiface/p4rt_translator.go index d108285e3..ed1898e93 100644 --- a/pfcpiface/p4rt_translator.go +++ b/pfcpiface/p4rt_translator.go @@ -523,10 +523,10 @@ func (t *P4rtTranslator) BuildApplicationsTableEntry(pdr pdr, internalAppID uint if pdr.srcIface == access { appIP, appIPMask = pdr.appFilter.dstIP, pdr.appFilter.dstIPMask - appPort = pdr.appFilter.dstPortFilter + appPort = pdr.appFilter.dstPortRange } else if pdr.srcIface == core { appIP, appIPMask = pdr.appFilter.srcIP, pdr.appFilter.srcIPMask - appPort = pdr.appFilter.srcPortFilter + appPort = pdr.appFilter.srcPortRange } appProto, appProtoMask := pdr.appFilter.proto, pdr.appFilter.protoMask diff --git a/pfcpiface/parse-pdr.go b/pfcpiface/parse-pdr.go index 2ba55f7e7..f33a2cd84 100644 --- a/pfcpiface/parse-pdr.go +++ b/pfcpiface/parse-pdr.go @@ -15,33 +15,33 @@ import ( ) // portRange encapsulates a L4 port range as seen in PDRs. A zero value portRange represents -// a wildcard match, but use of the dedicated new*PortFilter() functions is encouraged. +// a wildcard match, but use of the dedicated new*PortRange() functions is encouraged. type portRange struct { low uint16 high uint16 } -// newWildcardPortFilter returns a portRange that matches on every possible port, i.e., implements +// newWildcardPortRange returns a portRange that matches on every possible port, i.e., implements // no filtering. -func newWildcardPortFilter() portRange { +func newWildcardPortRange() portRange { return portRange{ low: 0, high: math.MaxUint16, } } -// newExactMatchPortFilter returns a portRange that matches on exactly the given port. -func newExactMatchPortFilter(port uint16) portRange { +// newExactMatchPortRange returns a portRange that matches on exactly the given port. +func newExactMatchPortRange(port uint16) portRange { return portRange{ low: port, high: port, } } -// newRangeMatchPortFilter returns a portRange that matches on the given range [low, high]. +// newRangeMatchPortRange returns a portRange that matches on the given range [low, high]. // low must be smaller than high. Creating exact and wildcard matches with this function is // possible, but use of the dedicated functions is encouraged. -func newRangeMatchPortFilter(low, high uint16) portRange { +func newRangeMatchPortRange(low, high uint16) portRange { if low > high { return portRange{} } @@ -185,14 +185,14 @@ type portRangeTernaryCartesianProduct struct { dstPort, dstMask uint16 } -// CreatePortFilterCartesianProduct converts two port ranges into a list of ternary +// CreatePortRangeCartesianProduct converts two port ranges into a list of ternary // rules covering the same range. -func CreatePortFilterCartesianProduct(src, dst portRange) ([]portRangeTernaryCartesianProduct, error) { +func CreatePortRangeCartesianProduct(src, dst portRange) ([]portRangeTernaryCartesianProduct, error) { // A single range rule can result in multiple ternary ones. To cover the same range of packets, // we need to create the Cartesian product of src and dst rules. For now, we only allow one true // range match to keep the complexity in check. if src.isRangeMatch() && dst.isRangeMatch() { - return nil, ErrInvalidArgumentWithReason("CreatePortFilterCartesianProduct", + return nil, ErrInvalidArgumentWithReason("CreatePortRangeCartesianProduct", src, "src and dst ports cannot both be a range match") } @@ -257,11 +257,11 @@ func CreatePortFilterCartesianProduct(src, dst portRange) ([]portRangeTernaryCar } type applicationFilter struct { - srcIP uint32 - dstIP uint32 - srcPortFilter portRange - dstPortFilter portRange - proto uint8 + srcIP uint32 + dstIP uint32 + srcPortRange portRange + dstPortRange portRange + proto uint8 srcIPMask uint32 dstIPMask uint32 @@ -302,7 +302,7 @@ func needAllocIP(ueIPaddr *ie.UEIPAddressFields) bool { func (af applicationFilter) String() string { return fmt.Sprintf("ApplicationFilter(srcIP=%v/%x, dstIP=%v/%x, proto=%v/%x, srcPort=%v, dstPort=%v)", af.srcIP, af.srcIPMask, af.dstIP, af.dstIPMask, af.proto, - af.protoMask, af.srcPortFilter, af.dstPortFilter) + af.protoMask, af.srcPortRange, af.dstPortRange) } func (p pdr) String() string { @@ -316,8 +316,8 @@ func (p pdr) String() string { func (p pdr) IsAppFilterEmpty() bool { return p.appFilter.proto == 0 && - ((p.IsUplink() && p.appFilter.dstIP == 0 && p.appFilter.dstPortFilter.isWildcardMatch()) || - (p.IsDownlink() && p.appFilter.srcIP == 0 && p.appFilter.srcPortFilter.isWildcardMatch())) + ((p.IsUplink() && p.appFilter.dstIP == 0 && p.appFilter.dstPortRange.isWildcardMatch()) || + (p.IsDownlink() && p.appFilter.srcIP == 0 && p.appFilter.srcPortRange.isWildcardMatch())) } func (p pdr) IsUplink() bool { @@ -442,8 +442,8 @@ func (p *pdr) parsePDI(seid uint64, pdiIEs []*ie.IE, appPFDs map[string]appPFD, p.appFilter.dstIPMask = ipMask2int(ipf.dst.IPNet.Mask) p.appFilter.srcIP = ip2int(ipf.src.IPNet.IP) p.appFilter.srcIPMask = ipMask2int(ipf.src.IPNet.Mask) - p.appFilter.dstPortFilter = ipf.dst.ports - p.appFilter.srcPortFilter = ipf.src.ports + p.appFilter.dstPortRange = ipf.dst.ports + p.appFilter.srcPortRange = ipf.src.ports break } @@ -480,26 +480,26 @@ func (p *pdr) parsePDI(seid uint64, pdiIEs []*ie.IE, appPFDs map[string]appPFD, p.appFilter.dstIPMask = ipMask2int(ipf.dst.IPNet.Mask) p.appFilter.srcIP = ip2int(ipf.src.IPNet.IP) p.appFilter.srcIPMask = ipMask2int(ipf.src.IPNet.Mask) - p.appFilter.dstPortFilter = ipf.dst.ports - p.appFilter.srcPortFilter = ipf.src.ports + p.appFilter.dstPortRange = ipf.dst.ports + p.appFilter.srcPortRange = ipf.src.ports // FIXME: temporary workaround for SDF Filter, // remove once we meet spec compliance - p.appFilter.srcPortFilter = p.appFilter.dstPortFilter - p.appFilter.dstPortFilter = newWildcardPortFilter() + p.appFilter.srcPortRange = p.appFilter.dstPortRange + p.appFilter.dstPortRange = newWildcardPortRange() } else if p.srcIface == access { p.appFilter.srcIP = ip2int(ipf.dst.IPNet.IP) p.appFilter.srcIPMask = ipMask2int(ipf.dst.IPNet.Mask) p.appFilter.dstIP = ip2int(ipf.src.IPNet.IP) p.appFilter.dstIPMask = ipMask2int(ipf.src.IPNet.Mask) // Ports are flipped for access PDRs - p.appFilter.dstPortFilter = ipf.src.ports - p.appFilter.srcPortFilter = ipf.dst.ports + p.appFilter.dstPortRange = ipf.src.ports + p.appFilter.srcPortRange = ipf.dst.ports // FIXME: temporary workaround for SDF Filter, // remove once we meet spec compliance - p.appFilter.dstPortFilter = p.appFilter.srcPortFilter - p.appFilter.srcPortFilter = newWildcardPortFilter() + p.appFilter.dstPortRange = p.appFilter.srcPortRange + p.appFilter.srcPortRange = newWildcardPortRange() } } } diff --git a/pfcpiface/parse-pdr_test.go b/pfcpiface/parse-pdr_test.go index fd550c5b2..14a5eb5b9 100644 --- a/pfcpiface/parse-pdr_test.go +++ b/pfcpiface/parse-pdr_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" ) -func Test_CreatePortFilterCartesianProduct(t *testing.T) { +func Test_CreatePortRangeCartesianProduct(t *testing.T) { type args struct { src portRange dst portRange @@ -21,7 +21,7 @@ func Test_CreatePortFilterCartesianProduct(t *testing.T) { wantErr bool }{ {name: "exact ranges", - args: args{src: newExactMatchPortFilter(5000), dst: newExactMatchPortFilter(80)}, + args: args{src: newExactMatchPortRange(5000), dst: newExactMatchPortRange(80)}, want: []portRangeTernaryCartesianProduct{{ srcPort: 5000, srcMask: math.MaxUint16, @@ -30,7 +30,7 @@ func Test_CreatePortFilterCartesianProduct(t *testing.T) { }}, wantErr: false}, {name: "wildcard dst range", - args: args{src: newExactMatchPortFilter(10), dst: newWildcardPortFilter()}, + args: args{src: newExactMatchPortRange(10), dst: newWildcardPortRange()}, want: []portRangeTernaryCartesianProduct{{ srcPort: 10, srcMask: math.MaxUint16, @@ -39,7 +39,7 @@ func Test_CreatePortFilterCartesianProduct(t *testing.T) { }}, wantErr: false}, {name: "true range src range", - args: args{src: newRangeMatchPortFilter(1, 3), dst: newExactMatchPortFilter(80)}, + args: args{src: newRangeMatchPortRange(1, 3), dst: newExactMatchPortRange(80)}, want: []portRangeTernaryCartesianProduct{ { srcPort: 0x1, @@ -61,7 +61,7 @@ func Test_CreatePortFilterCartesianProduct(t *testing.T) { }}, wantErr: false}, {name: "invalid double range", - args: args{src: newRangeMatchPortFilter(10, 20), dst: newRangeMatchPortFilter(80, 85)}, + args: args{src: newRangeMatchPortRange(10, 20), dst: newRangeMatchPortRange(80, 85)}, want: nil, wantErr: true}, } @@ -69,26 +69,26 @@ func Test_CreatePortFilterCartesianProduct(t *testing.T) { for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { - got, err := CreatePortFilterCartesianProduct(tt.args.src, tt.args.dst) + got, err := CreatePortRangeCartesianProduct(tt.args.src, tt.args.dst) if (err != nil) != tt.wantErr { - t.Errorf("CreatePortFilterCartesianProduct() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("CreatePortRangeCartesianProduct() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("CreatePortFilterCartesianProduct() got = %v, want %v", got, tt.want) + t.Errorf("CreatePortRangeCartesianProduct() got = %v, want %v", got, tt.want) } }, ) } } -func Test_defaultPortFilter(t *testing.T) { +func Test_defaultPortRange(t *testing.T) { t.Run("default constructed is wildcard", func(t *testing.T) { assert.True(t, portRange{}.isWildcardMatch(), "default portRange is wildcard") }) } -func Test_newWildcardPortFilter(t *testing.T) { +func Test_newWildcardPortRange(t *testing.T) { tests := []struct { name string want portRange @@ -98,8 +98,8 @@ func Test_newWildcardPortFilter(t *testing.T) { for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { - if got := newWildcardPortFilter(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("newWildcardPortFilter() = %v, want %v", got, tt.want) + if got := newWildcardPortRange(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("newWildcardPortRange() = %v, want %v", got, tt.want) } }, ) @@ -368,11 +368,11 @@ func Test_portRange_Width(t *testing.T) { pr portRange want uint16 }{ - {name: "wildcard", pr: newWildcardPortFilter(), want: math.MaxUint16}, + {name: "wildcard", pr: newWildcardPortRange(), want: math.MaxUint16}, {name: "zero value", pr: portRange{}, want: math.MaxUint16}, - {name: "exact match", pr: newExactMatchPortFilter(100), want: 1}, - {name: "range match", pr: newRangeMatchPortFilter(10, 12), want: 3}, - {name: "range single match", pr: newRangeMatchPortFilter(1000, 1000), want: 1}, + {name: "exact match", pr: newExactMatchPortRange(100), want: 1}, + {name: "range match", pr: newRangeMatchPortRange(10, 12), want: 3}, + {name: "range single match", pr: newRangeMatchPortRange(1000, 1000), want: 1}, } for _, tt := range tests { t.Run( diff --git a/pfcpiface/parse-sdf.go b/pfcpiface/parse-sdf.go index 31d0cd311..6cadef8aa 100644 --- a/pfcpiface/parse-sdf.go +++ b/pfcpiface/parse-sdf.go @@ -71,7 +71,7 @@ func (ep *endpoint) parsePort(port string) error { return ErrInvalidArgumentWithReason("port", port, "invalid port range") } - ep.ports = newRangeMatchPortFilter(uint16(low), uint16(high)) + ep.ports = newRangeMatchPortRange(uint16(low), uint16(high)) return nil } @@ -84,8 +84,8 @@ type ipFilterRule struct { func newIpFilterRule() *ipFilterRule { return &ipFilterRule{ - src: endpoint{ports: newWildcardPortFilter()}, - dst: endpoint{ports: newWildcardPortFilter()}, + src: endpoint{ports: newWildcardPortRange()}, + dst: endpoint{ports: newWildcardPortRange()}, } } diff --git a/pfcpiface/up4.go b/pfcpiface/up4.go index 064162ca7..a687da53e 100644 --- a/pfcpiface/up4.go +++ b/pfcpiface/up4.go @@ -573,7 +573,7 @@ func (up4 *UP4) allocateInternalApplicationID(app application) (uint8, error) { func (up4 *UP4) releaseInternalApplicationID(appFilter applicationFilter) { app := application{ appIP: appFilter.srcIP, - appL4Port: appFilter.srcPortFilter, + appL4Port: appFilter.srcPortRange, appProto: appFilter.proto, } @@ -589,12 +589,12 @@ func (up4 *UP4) getOrAllocateInternalApplicationID(pdr pdr) (uint8, error) { if pdr.IsUplink() { app = application{ appIP: pdr.appFilter.dstIP, - appL4Port: pdr.appFilter.dstPortFilter, + appL4Port: pdr.appFilter.dstPortRange, } } else if pdr.IsDownlink() { app = application{ appIP: pdr.appFilter.srcIP, - appL4Port: pdr.appFilter.srcPortFilter, + appL4Port: pdr.appFilter.srcPortRange, } } From 8f3e3ed959faa9f894d6312387e6a10529cfbb33 Mon Sep 17 00:00:00 2001 From: Maximilian Pudelko Date: Sat, 5 Feb 2022 15:14:28 -0800 Subject: [PATCH 17/18] Add license header --- pfcpiface/parse-pdr_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pfcpiface/parse-pdr_test.go b/pfcpiface/parse-pdr_test.go index 14a5eb5b9..c05bdaf52 100644 --- a/pfcpiface/parse-pdr_test.go +++ b/pfcpiface/parse-pdr_test.go @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2022 Open Networking Foundation + package main import ( From 0cc1f3bcc4e7804271f178c8f4465d099304161a Mon Sep 17 00:00:00 2001 From: pudelkoM Date: Mon, 7 Feb 2022 08:59:07 -0800 Subject: [PATCH 18/18] Trigger CI