Skip to content

Commit

Permalink
Fix networkpolicy related antctl commands (antrea-io#6487)
Browse files Browse the repository at this point in the history
This commit contains numerous fixes for antctl, including the get ovsflows
and get networkpolicy commands:

1. Update the `antctl get networkpolicy` flag type=ANP to point the correct
   AdminNetworkPolicy type since ANP<->AntreaNetworkPolicy mapping has been
   deprecated.
2. Update the `antctl get ovsflows` command so that when dumping flows for
   a specific policy, a type is now required to eliminate ambiguity.
3. Since v1.13 the `antctl get ovsflows` command will not work properly for
   dumping networkpolicy flows. This is due to the matcher for dumping flows
   include priority, which is not supported by openvswitch. This PR fixes
   this issue.

Signed-off-by: Dyanngg <[email protected]>
  • Loading branch information
Dyanngg authored and hangyan committed Oct 29, 2024
1 parent 1e55900 commit 5b0f721
Show file tree
Hide file tree
Showing 13 changed files with 415 additions and 134 deletions.
27 changes: 18 additions & 9 deletions docs/antctl.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ output format. The `NAME` of a control plane NetworkPolicy is the UID of its sou
NetworkPolicy.

```bash
antctl get networkpolicy [NAME] [-n NAMESPACE] [-o yaml]
antctl get networkpolicy [NAME] [-n NAMESPACE] [-T K8sNP|ACNP|ANNP|ANP|BANP] [-o yaml]
antctl get appliedtogroup [NAME] [-o yaml]
antctl get addressgroup [NAME] [-o yaml]
```
Expand Down Expand Up @@ -350,7 +350,7 @@ in the specified OVS flow tables, or all or the specified OVS groups.
antctl get ovsflows
antctl get ovsflows -p POD -n NAMESPACE
antctl get ovsflows -S SERVICE -n NAMESPACE
antctl get ovsflows -N NETWORKPOLICY -n NAMESPACE
antctl get ovsflows [-n NAMESPACE] -N NETWORKPOLICY --type NETWORKPOLICY_TYPE
antctl get ovsflows -T TABLE_A,TABLE_B
antctl get ovsflows -T TABLE_A,TABLE_B_NUM
antctl get ovsflows -G all
Expand Down Expand Up @@ -381,13 +381,22 @@ kube-system kube-dns 160ea6d7-0234-5d1d-8ea0-b703d0aa3b46 1
# Dump OVS flows of NetworkPolicy "kube-dns"
$ antctl get of -N kube-dns -n kube-system
FLOW
table=90, n_packets=0, n_bytes=0, priority=190,conj_id=1,ip actions=resubmit(,105)
table=90, n_packets=0, n_bytes=0, priority=200,ip actions=conjunction(1,1/3)
table=90, n_packets=0, n_bytes=0, priority=200,ip,reg1=0x5 actions=conjunction(2,2/3),conjunction(1,2/3)
table=90, n_packets=0, n_bytes=0, priority=200,udp,tp_dst=53 actions=conjunction(1,3/3)
table=90, n_packets=0, n_bytes=0, priority=200,tcp,tp_dst=53 actions=conjunction(1,3/3)
table=90, n_packets=0, n_bytes=0, priority=200,tcp,tp_dst=9153 actions=conjunction(1,3/3)
table=100, n_packets=0, n_bytes=0, priority=200,ip,reg1=0x5 actions=drop
table=IngressRule, n_packets=0, n_bytes=0, priority=190,conj_id=1,ip actions=set_field:0x1->reg5,ct(commit,table=IngressMetric,zone=65520,exec(set_field:0x1/0xffffffff->ct_label))
table=IngressRule, n_packets=0, n_bytes=0, priority=200,ip actions=conjunction(1,1/3)
table=IngressRule, n_packets=0, n_bytes=0, priority=200,ip,reg1=0x5 actions=conjunction(2,2/3),conjunction(1,2/3)
table=IngressRule, n_packets=0, n_bytes=0, priority=200,udp,tp_dst=53 actions=conjunction(1,3/3)
table=IngressRule, n_packets=0, n_bytes=0, priority=200,tcp,tp_dst=53 actions=conjunction(1,3/3)
table=IngressRule, n_packets=0, n_bytes=0, priority=200,tcp,tp_dst=9153 actions=conjunction(1,3/3)
table=IngressDefaultRule, n_packets=0, n_bytes=0, priority=200,ip,reg1=0x5 actions=drop
# Dump OVS flows of AntreaNetworkPolicy "test-annp"
$ antctl get ovsflows -N test-annp -n default --type ANNP
FLOW
table=AntreaPolicyIngressRule, n_packets=0, n_bytes=0, priority=14900,conj_id=6 actions=set_field:0x6->reg3,set_field:0x400/0x400->reg0,goto_table:IngressMetric
table=AntreaPolicyIngressRule, n_packets=0, n_bytes=0, priority=14900,ip,nw_src=10.20.1.8 actions=conjunction(6,1/3)
table=AntreaPolicyIngressRule, n_packets=0, n_bytes=0, priority=14900,ip,nw_src=10.20.2.8 actions=conjunction(6,1/3)
table=AntreaPolicyIngressRule, n_packets=0, n_bytes=0, priority=14900,reg1=0x3 actions=conjunction(6,2/3)
table=AntreaPolicyIngressRule, n_packets=0, n_bytes=0, priority=14900,tcp,tp_dst=443 actions=conjunction(6,3/3)
```

### OVS packet tracing
Expand Down
21 changes: 8 additions & 13 deletions pkg/agent/apiserver/handlers/networkpolicy/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,6 @@ func HandleFunc(aq agentquerier.AgentQuerier) http.HandlerFunc {
}
}

// From user shorthand input to cpv1beta1.NetworkPolicyType
var mapToNetworkPolicyType = map[string]cpv1beta.NetworkPolicyType{
"NP": cpv1beta.K8sNetworkPolicy,
"K8SNP": cpv1beta.K8sNetworkPolicy,
"ACNP": cpv1beta.AntreaClusterNetworkPolicy,
"ANNP": cpv1beta.AntreaNetworkPolicy,
"ANP": cpv1beta.AntreaNetworkPolicy,
}

// Create a Network Policy Filter from URL Query
func newFilterFromURLQuery(query url.Values) (*querier.NetworkPolicyQueryFilter, string, error) {
namespace, pod := query.Get("namespace"), query.Get("pod")
Expand All @@ -77,9 +68,13 @@ func newFilterFromURLQuery(query url.Values) (*querier.NetworkPolicyQueryFilter,
}
}
strSourceType := strings.ToUpper(query.Get("type"))
npSourceType, ok := mapToNetworkPolicyType[strSourceType]
if strSourceType != "" && !ok {
return nil, "", fmt.Errorf("invalid policy source type. Valid values are K8sNP, ACNP, ANNP and ANP (deprecated)")
var policyType cpv1beta.NetworkPolicyType
if strSourceType != "" {
npSourceType, ok := querier.NetworkPolicyTypeMap[strSourceType]
if !ok {
return nil, "", fmt.Errorf("unknown policy type. Valid types are %v", querier.GetNetworkPolicyTypeShorthands())
}
policyType = npSourceType
}
source := query.Get("source")
name := query.Get("name")
Expand All @@ -90,6 +85,6 @@ func newFilterFromURLQuery(query url.Values) (*querier.NetworkPolicyQueryFilter,
Name: name,
SourceName: source,
Namespace: namespace,
SourceType: npSourceType,
SourceType: policyType,
}, pod, nil
}
63 changes: 50 additions & 13 deletions pkg/agent/apiserver/handlers/ovsflows/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package ovsflows

import (
"encoding/json"
"fmt"
"net/http"
"sort"
"strconv"
Expand All @@ -26,6 +27,7 @@ import (
"antrea.io/antrea/pkg/agent/apis"
"antrea.io/antrea/pkg/agent/openflow"
agentquerier "antrea.io/antrea/pkg/agent/querier"
cpv1beta "antrea.io/antrea/pkg/apis/controlplane/v1beta2"
binding "antrea.io/antrea/pkg/ovs/openflow"
"antrea.io/antrea/pkg/querier"
)
Expand All @@ -35,10 +37,12 @@ var (
getFlowTableName = openflow.GetFlowTableName
getFlowTableID = openflow.GetFlowTableID
getFlowTableList = openflow.GetTableList

errAmbiguousQuery = fmt.Errorf("query is ambiguous and matches more than one policy")
)

func dumpMatchedFlows(aq agentquerier.AgentQuerier, flowKeys []string) ([]apis.OVSFlowResponse, error) {
resps := []apis.OVSFlowResponse{}
var resps []apis.OVSFlowResponse
for _, f := range flowKeys {
flowStr, err := aq.GetOVSCtlClient().DumpMatchedFlow(f)
if err != nil {
Expand All @@ -53,7 +57,7 @@ func dumpMatchedFlows(aq agentquerier.AgentQuerier, flowKeys []string) ([]apis.O
}

func dumpFlows(aq agentquerier.AgentQuerier, table uint8) ([]apis.OVSFlowResponse, error) {
resps := []apis.OVSFlowResponse{}
var resps []apis.OVSFlowResponse
var flowStrs []string
var err error
if table != binding.TableIDAll {
Expand Down Expand Up @@ -170,19 +174,27 @@ func getServiceFlows(aq agentquerier.AgentQuerier, serviceName, namespace string
return append(resps, groupResps...), nil
}

func getNetworkPolicyFlows(aq agentquerier.AgentQuerier, npName, namespace string) ([]apis.OVSFlowResponse, error) {
if len(aq.GetNetworkPolicyInfoQuerier().GetNetworkPolicies(&querier.NetworkPolicyQueryFilter{SourceName: npName, Namespace: namespace})) == 0 {
func getNetworkPolicyFlows(aq agentquerier.AgentQuerier, npName, namespace string, policyType cpv1beta.NetworkPolicyType) ([]apis.OVSFlowResponse, error) {
npFilter := &querier.NetworkPolicyQueryFilter{
SourceName: npName,
Namespace: namespace,
SourceType: policyType,
}
nps := aq.GetNetworkPolicyInfoQuerier().GetNetworkPolicies(npFilter)
if len(nps) == 0 {
// NetworkPolicy not found.
return nil, nil
} else if len(nps) > 1 {
return nil, errAmbiguousQuery
}

flowKeys := aq.GetOpenflowClient().GetNetworkPolicyFlowKeys(npName, namespace)
namespace, policyType = nps[0].SourceRef.Namespace, nps[0].SourceRef.Type
flowKeys := aq.GetOpenflowClient().GetNetworkPolicyFlowKeys(npName, namespace, policyType)
return dumpMatchedFlows(aq, flowKeys)
}

func getTableNames(aq agentquerier.AgentQuerier) []apis.OVSFlowResponse {
resps := []apis.OVSFlowResponse{}
names := []string{}
func getTableNames() []apis.OVSFlowResponse {
var resps []apis.OVSFlowResponse
var names []string
for _, t := range getFlowTableList() {
names = append(names, t.GetName())
}
Expand All @@ -201,6 +213,7 @@ func HandleFunc(aq agentquerier.AgentQuerier) http.HandlerFunc {
pod := r.URL.Query().Get("pod")
service := r.URL.Query().Get("service")
networkPolicy := r.URL.Query().Get("networkpolicy")
policyType := strings.ToUpper(r.URL.Query().Get("type"))
namespace := r.URL.Query().Get("namespace")
table := r.URL.Query().Get("table")
groups := r.URL.Query().Get("groups")
Expand All @@ -214,16 +227,31 @@ func HandleFunc(aq agentquerier.AgentQuerier) http.HandlerFunc {
}

if tableNamesOnly {
resps = getTableNames(aq)
resps = getTableNames()
encodeResp()
return
}

if (pod != "" || service != "" || networkPolicy != "") && namespace == "" {
if (pod != "" || service != "") && namespace == "" {
http.Error(w, "namespace must be provided", http.StatusBadRequest)
return
}

if networkPolicy != "" && policyType != "" {
_, ok := querier.NetworkPolicyTypeMap[policyType]
if !ok {
errorMsg := fmt.Sprintf("unknown policy type. Valid types are %v", querier.GetNetworkPolicyTypeShorthands())
http.Error(w, errorMsg, http.StatusBadRequest)
return
}
if querier.NamespaceScopedPolicyTypes.Has(policyType) && namespace == "" {
http.Error(w, "policy Namespace must be provided for policy type "+policyType, http.StatusBadRequest)
return
}
if !querier.NamespaceScopedPolicyTypes.Has(policyType) && namespace != "" {
http.Error(w, "policy Namespace should not be provided for cluster-scoped policy type "+policyType, http.StatusBadRequest)
return
}
}
if pod == "" && service == "" && networkPolicy == "" && namespace == "" && table == "" && groups == "" {
resps, err = dumpFlows(aq, binding.TableIDAll)
} else if pod != "" {
Expand All @@ -236,7 +264,16 @@ func HandleFunc(aq agentquerier.AgentQuerier) http.HandlerFunc {
}
resps, err = getServiceFlows(aq, service, namespace)
} else if networkPolicy != "" {
resps, err = getNetworkPolicyFlows(aq, networkPolicy, namespace)
var cpPolicyType cpv1beta.NetworkPolicyType
if policyType != "" {
// policyType string has already been validated above
cpPolicyType = querier.NetworkPolicyTypeMap[policyType]
}
resps, err = getNetworkPolicyFlows(aq, networkPolicy, namespace, cpPolicyType)
if err == errAmbiguousQuery {
http.Error(w, errAmbiguousQuery.Error(), http.StatusBadRequest)
return
}
} else if table != "" {
resps, err = getTableFlows(aq, table)
if err == nil && resps == nil {
Expand Down
Loading

0 comments on commit 5b0f721

Please sign in to comment.