Skip to content

Commit 0d290e0

Browse files
authored
Merge pull request #119 from asimeth-do/udp-matching
Add ability to match UDP source/destination ports
2 parents 4a6a687 + 885762a commit 0d290e0

File tree

5 files changed

+312
-9
lines changed

5 files changed

+312
-9
lines changed

AUTHORS

+1
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ Kei Nohguchi <[email protected]>
1414
Neal Shrader <[email protected]>
1515
Sangeetha Srikanth <[email protected]>
1616
Franck Rupin <[email protected]>
17+
Adam Simeth <[email protected]>

ovs/match.go

+135-8
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ const (
7575
tunTTL = "tun_ttl"
7676
tunv6DST = "tun_ipv6_dst"
7777
tunv6SRC = "tun_ipv6_src"
78+
udpDST = "udp_dst"
79+
udpSRC = "udp_src"
7880
vlanTCI1 = "vlan_tci1"
7981
vlanTCI = "vlan_tci"
8082
)
@@ -879,8 +881,7 @@ func (m *arpProtocolAddressMatch) GoString() string {
879881
return fmt.Sprintf("ovs.ARPTargetProtocolAddress(%q)", m.ip)
880882
}
881883

882-
// TransportSourcePort matches packets with a transport layer (TCP/UDP) source
883-
// port matching port.
884+
// TransportSourcePort matches packets with a TCP source port matching port.
884885
func TransportSourcePort(port uint16) Match {
885886
return &transportPortMatch{
886887
srcdst: source,
@@ -889,8 +890,7 @@ func TransportSourcePort(port uint16) Match {
889890
}
890891
}
891892

892-
// TransportDestinationPort matches packets with a transport layer (TCP/UDP)
893-
// destination port matching port.
893+
// TransportDestinationPort matches packets with a TCP destination port matching port.
894894
func TransportDestinationPort(port uint16) Match {
895895
return &transportPortMatch{
896896
srcdst: destination,
@@ -899,8 +899,7 @@ func TransportDestinationPort(port uint16) Match {
899899
}
900900
}
901901

902-
// TransportSourceMaskedPort matches packets with a transport layer (TCP/UDP)
903-
// source port matching a masked port range.
902+
// TransportSourceMaskedPort matches packets with TCP source port matching a masked port range.
904903
func TransportSourceMaskedPort(port uint16, mask uint16) Match {
905904
return &transportPortMatch{
906905
srcdst: source,
@@ -909,8 +908,7 @@ func TransportSourceMaskedPort(port uint16, mask uint16) Match {
909908
}
910909
}
911910

912-
// TransportDestinationMaskedPort matches packets with a transport layer (TCP/UDP)
913-
// destination port matching a masked port range.
911+
// TransportDestinationMaskedPort matches packets with a TCP destination port matching a masked port range.
914912
func TransportDestinationMaskedPort(port uint16, mask uint16) Match {
915913
return &transportPortMatch{
916914
srcdst: destination,
@@ -919,6 +917,124 @@ func TransportDestinationMaskedPort(port uint16, mask uint16) Match {
919917
}
920918
}
921919

920+
// UDPSourcePort matches packets with a UDP source port matching port.
921+
func UDPSourcePort(port uint16) Match {
922+
return &udpPortMatch{
923+
srcdst: source,
924+
port: port,
925+
mask: 0,
926+
}
927+
}
928+
929+
// UDPDestinationPort matches packets with a UDP destination port matching port.
930+
func UDPDestinationPort(port uint16) Match {
931+
return &udpPortMatch{
932+
srcdst: destination,
933+
port: port,
934+
mask: 0,
935+
}
936+
}
937+
938+
// UDPSourceMaskedPort matches packets with UDP source port matching a masked port range.
939+
func UDPSourceMaskedPort(port uint16, mask uint16) Match {
940+
return &udpPortMatch{
941+
srcdst: source,
942+
port: port,
943+
mask: mask,
944+
}
945+
}
946+
947+
// UDPDestinationMaskedPort matches packets with a UDP destination port matching a masked port range.
948+
func UDPDestinationMaskedPort(port uint16, mask uint16) Match {
949+
return &udpPortMatch{
950+
srcdst: destination,
951+
port: port,
952+
mask: mask,
953+
}
954+
}
955+
956+
// A udpPortMatch is a Match returned by Udp{Source,Destination}Port.
957+
type udpPortMatch struct {
958+
srcdst string
959+
port uint16
960+
mask uint16
961+
}
962+
963+
var _ Match = &udpPortMatch{}
964+
965+
// A udpPortRange reprsents the start and end values of a udp protocol port range.
966+
type udpPortRange struct {
967+
srcdst string
968+
startPort uint16
969+
endPort uint16
970+
}
971+
972+
// UDPDestinationPortRange represent a port range intended for a UDP protocol destination port.
973+
func UDPDestinationPortRange(startPort uint16, endPort uint16) TransportPortRanger {
974+
return &udpPortRange{
975+
srcdst: destination,
976+
startPort: startPort,
977+
endPort: endPort,
978+
}
979+
}
980+
981+
// UDPSourcePortRange represent a port range intended for a UDP protocol source port.
982+
func UDPSourcePortRange(startPort uint16, endPort uint16) TransportPortRanger {
983+
return &udpPortRange{
984+
srcdst: source,
985+
startPort: startPort,
986+
endPort: endPort,
987+
}
988+
}
989+
990+
// MaskedPorts returns the represented port ranges as an array of bitwise matches.
991+
func (pr *udpPortRange) MaskedPorts() ([]Match, error) {
992+
portRange := PortRange{
993+
Start: pr.startPort,
994+
End: pr.endPort,
995+
}
996+
997+
bitRanges, err := portRange.BitwiseMatch()
998+
if err != nil {
999+
return nil, err
1000+
}
1001+
1002+
var ports []Match
1003+
1004+
for _, br := range bitRanges {
1005+
maskedPortRange := &udpPortMatch{
1006+
srcdst: pr.srcdst,
1007+
port: br.Value,
1008+
mask: br.Mask,
1009+
}
1010+
ports = append(ports, maskedPortRange)
1011+
}
1012+
1013+
return ports, nil
1014+
}
1015+
1016+
// MarshalText implements Match.
1017+
func (m *udpPortMatch) MarshalText() ([]byte, error) {
1018+
return matchUDPPort(m.srcdst, m.port, m.mask)
1019+
}
1020+
1021+
// GoString implements Match.
1022+
func (m *udpPortMatch) GoString() string {
1023+
if m.mask > 0 {
1024+
if m.srcdst == source {
1025+
return fmt.Sprintf("ovs.UdpSourceMaskedPort(%#x, %#x)", m.port, m.mask)
1026+
}
1027+
1028+
return fmt.Sprintf("ovs.UdpDestinationMaskedPort(%#x, %#x)", m.port, m.mask)
1029+
}
1030+
1031+
if m.srcdst == source {
1032+
return fmt.Sprintf("ovs.UdpSourcePort(%d)", m.port)
1033+
}
1034+
1035+
return fmt.Sprintf("ovs.UdpDestinationPort(%d)", m.port)
1036+
}
1037+
9221038
// A transportPortMatch is a Match returned by Transport{Source,Destination}Port.
9231039
type transportPortMatch struct {
9241040
srcdst string
@@ -1491,6 +1607,17 @@ func matchTransportPort(srcdst string, port uint16, mask uint16) ([]byte, error)
14911607
return bprintf("tp_%s=0x%04x/0x%04x", srcdst, port, mask), nil
14921608
}
14931609

1610+
// matchUDPPort is the common implementation for
1611+
// Udp{Source,Destination}Port.
1612+
func matchUDPPort(srcdst string, port uint16, mask uint16) ([]byte, error) {
1613+
// No mask specified
1614+
if mask == 0 {
1615+
return bprintf("udp_%s=%d", srcdst, port), nil
1616+
}
1617+
1618+
return bprintf("udp_%s=0x%04x/0x%04x", srcdst, port, mask), nil
1619+
}
1620+
14941621
// IPFragFlag is a string type which can be used with the IPFragMatch.
14951622
type IPFragFlag string
14961623

ovs/match_test.go

+105
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,111 @@ func TestMatchTransportPortRange(t *testing.T) {
922922
}
923923
}
924924

925+
func TestMatchUdp(t *testing.T) {
926+
var tests = []struct {
927+
desc string
928+
m Match
929+
out string
930+
}{
931+
{
932+
desc: "source port 80",
933+
m: UDPSourcePort(80),
934+
out: "udp_src=80",
935+
},
936+
{
937+
desc: "source port 65535",
938+
m: UDPSourcePort(65535),
939+
out: "udp_src=65535",
940+
},
941+
{
942+
desc: "destination port 22",
943+
m: UDPDestinationPort(22),
944+
out: "udp_dst=22",
945+
},
946+
{
947+
desc: "destination port 8080",
948+
m: UDPDestinationPort(8080),
949+
out: "udp_dst=8080",
950+
},
951+
{
952+
desc: "source port range 16/0xfff0 (16-31)",
953+
m: UDPSourceMaskedPort(0x10, 0xfff0),
954+
out: "udp_src=0x0010/0xfff0",
955+
},
956+
{
957+
desc: "destination port range 16/0xfff0 (16-31)",
958+
m: UDPDestinationMaskedPort(0x10, 0xfff0),
959+
out: "udp_dst=0x0010/0xfff0",
960+
},
961+
}
962+
963+
for _, tt := range tests {
964+
t.Run(tt.desc, func(t *testing.T) {
965+
out, err := tt.m.MarshalText()
966+
if err != nil {
967+
t.Fatalf("unexpected error: %v", err)
968+
}
969+
970+
if want, got := tt.out, string(out); want != got {
971+
t.Fatalf("unexpected Match output:\n- want: %q\n- got: %q",
972+
want, got)
973+
}
974+
})
975+
}
976+
}
977+
978+
func TestMatchUdpPortRange(t *testing.T) {
979+
var tests = []struct {
980+
desc string
981+
pr TransportPortRanger
982+
m []Match
983+
}{
984+
{
985+
desc: "destination port range 16-31",
986+
pr: UDPDestinationPortRange(16, 31),
987+
m: []Match{
988+
UDPDestinationMaskedPort(0x10, 0xfff0),
989+
},
990+
},
991+
{
992+
desc: "source port range 16-31",
993+
pr: UDPSourcePortRange(16, 31),
994+
m: []Match{
995+
UDPSourceMaskedPort(0x10, 0xfff0),
996+
},
997+
},
998+
{
999+
desc: "destination port range 16-32",
1000+
pr: UDPDestinationPortRange(16, 32),
1001+
m: []Match{
1002+
UDPDestinationMaskedPort(0x10, 0xfff0),
1003+
UDPDestinationMaskedPort(0x20, 0xffff),
1004+
},
1005+
},
1006+
{
1007+
desc: "source port range 16-32",
1008+
pr: UDPSourcePortRange(16, 32),
1009+
m: []Match{
1010+
UDPSourceMaskedPort(0x10, 0xfff0),
1011+
UDPSourceMaskedPort(0x20, 0xffff),
1012+
},
1013+
},
1014+
}
1015+
1016+
for _, tt := range tests {
1017+
t.Run(tt.desc, func(t *testing.T) {
1018+
m, err := tt.pr.MaskedPorts()
1019+
if err != nil {
1020+
t.Fatalf("unexpected error: %v", err)
1021+
}
1022+
if want, got := tt.m, m; !reflect.DeepEqual(want, got) {
1023+
t.Fatalf("unexpected Match:\n- want: %q\n- got: %q",
1024+
want, got)
1025+
}
1026+
})
1027+
}
1028+
}
1029+
9251030
func TestMatchVLANTCI(t *testing.T) {
9261031
var tests = []struct {
9271032
desc string

ovs/matchparser.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func parseMatch(key string, value string) (Match, error) {
3535
return parseIntMatch(key, value, math.MaxUint8)
3636
case ctZone:
3737
return parseIntMatch(key, value, math.MaxUint16)
38-
case tpSRC, tpDST:
38+
case tpSRC, tpDST, udpSRC, udpDST:
3939
return parsePort(key, value, math.MaxUint16)
4040
case conjID:
4141
return parseIntMatch(key, value, math.MaxUint32)
@@ -215,6 +215,10 @@ func parsePort(key string, value string, max int) (Match, error) {
215215
return TransportSourceMaskedPort(uint16(values[0]), uint16(values[1])), nil
216216
case tpDST:
217217
return TransportDestinationMaskedPort(uint16(values[0]), uint16(values[1])), nil
218+
case udpSRC:
219+
return UDPSourceMaskedPort(uint16(values[0]), uint16(values[1])), nil
220+
case udpDST:
221+
return UDPDestinationMaskedPort(uint16(values[0]), uint16(values[1])), nil
218222
}
219223
// Return error if input is invalid
220224
return nil, fmt.Errorf("no action matched for %s=%s", key, value)

0 commit comments

Comments
 (0)