Skip to content

Commit

Permalink
Support portRange in CRDs (#1557)
Browse files Browse the repository at this point in the history
* Support portRange in CRDs

Add `endPort` at jsonPath spec.ingress/egress[*].ports[*].endPort of ACNP and ANP YAML. The internal `Service` will add `endPort` field as well.
To support port range, due to ovs format, [port]:[endPort] will be transformed into a list of port/mask with bitwise match. Antrea Agent will do this transformation using a third lib.
Add validation, UT, and e2e test.
  • Loading branch information
GraysonWu authored Dec 21, 2020
1 parent f86c262 commit 7a43f99
Show file tree
Hide file tree
Showing 36 changed files with 1,223 additions and 466 deletions.
8 changes: 8 additions & 0 deletions build/yamls/antrea-aks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down Expand Up @@ -189,6 +191,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down Expand Up @@ -359,6 +363,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down Expand Up @@ -426,6 +432,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down
8 changes: 8 additions & 0 deletions build/yamls/antrea-eks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down Expand Up @@ -189,6 +191,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down Expand Up @@ -359,6 +363,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down Expand Up @@ -426,6 +432,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down
8 changes: 8 additions & 0 deletions build/yamls/antrea-gke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down Expand Up @@ -189,6 +191,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down Expand Up @@ -359,6 +363,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down Expand Up @@ -426,6 +432,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down
8 changes: 8 additions & 0 deletions build/yamls/antrea-ipsec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down Expand Up @@ -189,6 +191,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down Expand Up @@ -359,6 +363,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down Expand Up @@ -426,6 +432,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down
8 changes: 8 additions & 0 deletions build/yamls/antrea.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down Expand Up @@ -189,6 +191,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down Expand Up @@ -359,6 +363,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down Expand Up @@ -426,6 +432,8 @@ spec:
ports:
items:
properties:
endPort:
type: integer
port:
x-kubernetes-int-or-string: true
protocol:
Expand Down
8 changes: 8 additions & 0 deletions build/yamls/base/crds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,8 @@ spec:
type: string
port:
x-kubernetes-int-or-string: true
endPort:
type: integer
from:
type: array
items:
Expand Down Expand Up @@ -391,6 +393,8 @@ spec:
type: string
port:
x-kubernetes-int-or-string: true
endPort:
type: integer
to:
type: array
items:
Expand Down Expand Up @@ -522,6 +526,8 @@ spec:
type: string
port:
x-kubernetes-int-or-string: true
endPort:
type: integer
from:
type: array
items:
Expand Down Expand Up @@ -572,6 +578,8 @@ spec:
type: string
port:
x-kubernetes-int-or-string: true
endPort:
type: integer
to:
type: array
items:
Expand Down
12 changes: 10 additions & 2 deletions docs/antrea-network-policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ spec:
ports:
- protocol: TCP
port: 8080
endPort: 9000
- protocol: TCP
port: 6379
name: AllowFromFrontend
enableLogging: false
egress:
Expand Down Expand Up @@ -266,7 +269,9 @@ default tier i.e. the "application" Tier.

**ingress**: Each ClusterNetworkPolicy may consist of zero or more ordered
set of ingress rules. Each rule, depending on the `action` field of the rule,
allows or drops traffic which matches both the `from` and `ports` sections.
allows or drops traffic which matches all `from`, `ports` sections.
Under `ports`, the optional field `endPort` can only be set when a numerical `port`
is set to represent a range of ports from `port` to `endPort` inclusive.
Also, each rule has an optional `name` field, which should be unique within
the policy describing the intention of this rule. If `name` is not provided for
a rule, it will be auto-generated by Antrea. The auto-generated name will be
Expand All @@ -284,7 +289,9 @@ be enforced in the order in which they are written.

**egress**: Each ClusterNetworkPolicy may consist of zero or more ordered set
of egress rules. Each rule, depending on the `action` field of the rule, allows
or drops traffic which matches both the `to` and `ports` sections.
or drops traffic which matches all `from`, `ports` sections.
Under `ports`, the optional field `endPort` can only be set when a numerical `port`
is set to represent a range of ports from `port` to `endPort` inclusive.
Also, each rule has an optional `name` field, which should be unique within
the policy describing the intention of this rule. If `name` is not provided for
a rule, it will be auto-generated by Antrea. The rule name auto-generation process
Expand Down Expand Up @@ -413,6 +420,7 @@ spec:
ports:
- protocol: TCP
port: 8080
endPort: 9000
name: AllowFromFrontend
enableLogging: false
egress:
Expand Down
71 changes: 56 additions & 15 deletions pkg/agent/openflow/network_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/vmware-tanzu/antrea/pkg/apis/controlplane/v1beta2"
secv1alpha1 "github.com/vmware-tanzu/antrea/pkg/apis/security/v1alpha1"
binding "github.com/vmware-tanzu/antrea/pkg/ovs/openflow"
thirdpartynp "github.com/vmware-tanzu/antrea/third_party/networkpolicy"
)

var (
Expand Down Expand Up @@ -212,8 +213,16 @@ func (m *conjunctiveMatch) generateGlobalMapKey() string {
}
case net.IPNet:
valueStr = v.String()
case types.BitRange:
bitRange := m.matchValue.(types.BitRange)
if bitRange.Mask != nil {
valueStr = fmt.Sprintf("%d/%d", bitRange.Value, *bitRange.Mask)
} else {
// To normalize the key, set full mask while a single port is provided.
valueStr = fmt.Sprintf("%d/65535", bitRange.Value)
}
default:
// The default cases include the matchValue is a Service port or an ofport Number.
// The default cases include the matchValue is an ofport Number.
valueStr = fmt.Sprintf("%s", m.matchValue)
}
if m.priority == nil {
Expand Down Expand Up @@ -616,26 +625,58 @@ func getServiceMatchType(protocol *v1beta2.Protocol, ipv4Enabled, ipv6Enabled bo
return matchKeys
}

func (c *clause) generateServicePortConjMatches(port v1beta2.Service, priority *uint16, ipv4Enabled, ipv6Enabled bool) []*conjunctiveMatch {
matchKeys := getServiceMatchType(port.Protocol, ipv4Enabled, ipv6Enabled)
// Match all ports with the given protocol type if the matchValue is not specified (value is 0).
matchValue := uint16(0)
if port.Port != nil {
matchValue = uint16(port.Port.IntVal)
}
func (c *clause) generateServicePortConjMatches(service v1beta2.Service, priority *uint16, ipv4Enabled, ipv6Enabled bool) []*conjunctiveMatch {
matchKeys := getServiceMatchType(service.Protocol, ipv4Enabled, ipv6Enabled)
ovsBitRanges := c.serviceToBitRanges(service)
var matches []*conjunctiveMatch
for _, matchKey := range matchKeys {
matches = append(matches,
&conjunctiveMatch{
tableID: c.ruleTable.GetID(),
matchKey: matchKey,
matchValue: matchValue,
priority: priority,
})
for _, ovsBitRange := range ovsBitRanges {
matches = append(matches,
&conjunctiveMatch{
tableID: c.ruleTable.GetID(),
matchKey: matchKey,
matchValue: ovsBitRange,
priority: priority,
})
}
}
return matches
}

// serviceToBitRanges converts a Service to a list of BitRange.
func (c *clause) serviceToBitRanges(service v1beta2.Service) []types.BitRange {
var ovsBitRanges []types.BitRange
// If `EndPort` is equal to `Port`, then treat it as single port case.
if service.EndPort != nil && *service.EndPort > service.Port.IntVal {
// Add several antrea range services based on a port range.
portRange := thirdpartynp.PortRange{Start: uint16(service.Port.IntVal), End: uint16(*service.EndPort)}
bitRanges, err := portRange.BitwiseMatch()
if err != nil {
klog.Errorf("Error when getting BitRanges from %v: %v", portRange, err)
return ovsBitRanges
}
for _, bitRange := range bitRanges {
curBitRange := bitRange
ovsBitRanges = append(ovsBitRanges, types.BitRange{
Value: curBitRange.Value,
Mask: &curBitRange.Mask,
})
}
} else if service.Port != nil {
// Add single antrea service based on a single port.
ovsBitRanges = append(ovsBitRanges, types.BitRange{
Value: uint16(service.Port.IntVal),
})
} else {
// Match all ports with the given protocol type if `Port` and `EndPort` are not
// specified (value is 0).
ovsBitRanges = append(ovsBitRanges, types.BitRange{
Value: uint16(0),
})
}
return ovsBitRanges
}

// addAddrFlows translates the specified addresses to conjunctiveMatchFlows, and returns the corresponding changes on the
// conjunctiveMatchFlows.
func (c *clause) addAddrFlows(client *client, addrType types.AddressType, addresses []types.Address, priority *uint16) []*conjMatchFlowContextChange {
Expand Down
7 changes: 4 additions & 3 deletions pkg/agent/openflow/network_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,10 +219,11 @@ func TestInstallPolicyRuleFlows(t *testing.T) {

ruleID3 := uint32(103)
port1 := intstr.FromInt(8080)
port2 := intstr.FromInt(8081)
port2 := intstr.FromInt(1000)
port3 := int32(1007)
tcpProtocol := v1beta2.ProtocolTCP
npPort1 := v1beta2.Service{Protocol: &tcpProtocol, Port: &port1}
npPort2 := v1beta2.Service{Protocol: &tcpProtocol, Port: &port2}
npPort2 := v1beta2.Service{Protocol: &tcpProtocol, Port: &port2, EndPort: &port3}
rule3 := &types.PolicyRule{
Direction: v1beta2.DirectionOut,
From: parseAddresses([]string{"192.168.1.40", "192.168.1.60"}),
Expand Down Expand Up @@ -665,7 +666,7 @@ func newMockRuleFlowBuilder(ctrl *gomock.Controller) *mocks.MockFlowBuilder {
ruleFlowBuilder.EXPECT().MatchSrcIP(gomock.Any()).Return(ruleFlowBuilder).AnyTimes()
ruleFlowBuilder.EXPECT().MatchInPort(gomock.Any()).Return(ruleFlowBuilder).AnyTimes()
ruleFlowBuilder.EXPECT().MatchRegRange(gomock.Any(), gomock.Any(), gomock.Any()).Return(ruleFlowBuilder).AnyTimes()
ruleFlowBuilder.EXPECT().MatchDstPort(gomock.Any(), gomock.Nil()).Return(ruleFlowBuilder).AnyTimes()
ruleFlowBuilder.EXPECT().MatchDstPort(gomock.Any(), gomock.Any()).Return(ruleFlowBuilder).AnyTimes()
ruleFlowBuilder.EXPECT().MatchConjID(gomock.Any()).Return(ruleFlowBuilder).AnyTimes()
ruleFlowBuilder.EXPECT().MatchPriority(gomock.Any()).Return(ruleFlowBuilder).AnyTimes()
ruleAction = mocks.NewMockAction(ctrl)
Expand Down
6 changes: 3 additions & 3 deletions pkg/agent/openflow/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -1347,9 +1347,9 @@ func (c *client) addFlowMatch(fb binding.FlowBuilder, matchKey *types.MatchKey,
fallthrough
case MatchSCTPv6DstPort:
fb = fb.MatchProtocol(matchKey.GetOFProtocol())
portValue := matchValue.(uint16)
if portValue > 0 {
fb = fb.MatchDstPort(portValue, nil)
portValue := matchValue.(types.BitRange)
if portValue.Value > 0 {
fb = fb.MatchDstPort(portValue.Value, portValue.Mask)
}
}
return fb
Expand Down
Loading

0 comments on commit 7a43f99

Please sign in to comment.