console: HAS/HASNOT operator for filtering on ASPath

This commit is contained in:
Vincent Bernat
2022-09-26 13:31:37 +02:00
parent 9c90ee89f6
commit bd31b80cc0
5 changed files with 45 additions and 5 deletions

View File

@@ -163,7 +163,8 @@ guaranteed, so an URL may stop working after a few upgrades.
The filter language looks like SQL with a few variations. Fields
listed as dimensions can usually be used. Accepted operators are `=`,
`!=`, `<`, `<=`, `>`, `>=`, `IN`, `NOTIN`, `LIKE`, `UNLIKE`, `ILIKE`,
`IUNLIKE`, `<<`, `!<<` when they make sense. Here are a few examples:
`IUNLIKE`, `<<`, `!<<`, `HAS`, `HASNOT` when they make sense. Here are
a few examples:
- `InIfBoundary = external` only selects flows whose incoming
interface was classified as external. The value should not be
@@ -178,13 +179,19 @@ listed as dimensions can usually be used. Accepted operators are `=`,
specified subnet.
- `ExporterName LIKE th2-%` selects flows coming from routers
starting with `th2-`.
- `ASPath HAS AS1299` selects flows whose AS path contains 1299.
Field names are case-insensitive. Comments can also be added by using
`--` for single-line comments or enclosing them in `/*` and `*/`.
The final SQL query sent to ClickHouse is logged inside the console
after a successful request. It should be noted than using ports or
addresses prevent the use of aggregated data and are therefore slower.
after a successful request. It should be noted than using the
following fields will prevent use of aggregated data and therefore
will be slower:
- `SrcAddr` and `DstAddr`,
- `SrcPort` and `DstPort`,
- `DstASPath`
## Demo exporter service

View File

@@ -163,12 +163,15 @@ func (c *Component) filterCompleteHandlerFunc(gc *gin.Context) {
filterCompletion{"PIM", "protocol", true},
filterCompletion{"IPv4", "protocol", true},
filterCompletion{"IPv6", "protocol", true})
case "srcas", "dstas", "dst1stas", "dst2ndas", "dst3rdas":
case "srcas", "dstas", "dst1stas", "dst2ndas", "dst3rdas", "dstaspath":
results := []struct {
Label string `ch:"label"`
Detail string `ch:"detail"`
}{}
columnName := fixQueryColumnName(input.Column)
if columnName == "DstASPath" {
columnName = "DstAS"
}
sqlQuery := fmt.Sprintf(`
SELECT label, detail FROM (
SELECT concat('AS', toString(%s)) AS label, dictGet('asns', 'name', %s) AS detail, 1 AS rank

View File

@@ -42,6 +42,7 @@ ConditionExpr "conditional" ←
/ ConditionForwardingStatusExpr
/ ConditionPortExpr
/ ConditionASExpr
/ ConditionASPathExpr
/ ConditionETypeExpr
/ ConditionProtoExpr
/ ConditionPacketSizeExpr
@@ -147,6 +148,12 @@ RConditionASExpr "condition on AS number" ←
return fmt.Sprintf("%s (%s)", toString(operator), toString(value)), nil
}
ConditionASPathExpr "condition on AS path" ←
column:("DstASPath"i { return "DstASPath", nil }) _
KW_HAS _ value:ASN { return fmt.Sprintf("has(%s, %s)", toString(column), toString(value)), nil }
/ column:("DstASPath"i { return "DstASPath", nil }) _
KW_HASNOT _ value:ASN { return fmt.Sprintf("NOT has(%s, %s)", toString(column), toString(value)), nil }
ConditionETypeExpr "condition on Ethernet type" ←
column:("EType"i { return "EType", nil }) _
operator:("=" / "!=") _ value:("IPv4"i / "IPv6"i) {
@@ -260,6 +267,8 @@ KW_IN "IN operator" ← "IN"i !IdentStart { return "IN", nil }
KW_UNLIKE "UNLIKE operator" ← "UNLIKE"i !IdentStart { return "NOT LIKE", nil }
KW_IUNLIKE "IUNLIKE operator" ← "IUNLIKE"i !IdentStart { return "NOT ILIKE", nil }
KW_NOTIN "NOTIN operator" ← "NOTIN"i !IdentStart { return "NOT IN", nil }
KW_HAS "HAS operator" ← "HAS"i !IdentStart
KW_HASNOT "HASNOT operator" ← "HASNOT"i !IdentStart
SingleLineComment "comment" ← "--" ( !EOL SourceChar )*
MultiLineComment ← "/*" ( !"*/" SourceChar )* ("*/" / EOF {

View File

@@ -196,6 +196,8 @@ AND SrcAS = AS12322 -- Proxad ASN`,
output provider */ = 'telia'`,
Output: `OutIfProvider = 'telia'`,
},
{Input: `DstASPath HAS 65000`, Output: `has(DstASPath, 65000)`},
{Input: `DstASPath HASNOT 65000`, Output: `NOT has(DstASPath, 65000)`},
}
for _, tc := range cases {
got, err := Parse("", []byte(tc.Input), GlobalStore("meta", &tc.MetaIn))

View File

@@ -89,7 +89,8 @@ UNION DISTINCT
{"AS36987", "Google Kenya"},
{"AS41264", "Google Switzerland"},
}).
Return(nil)
Return(nil).
MinTimes(2).MaxTimes(2)
helpers.TestHTTPEndpoints(t, h.LocalAddr(), helpers.HTTPEndpointCases{
{
@@ -120,6 +121,7 @@ UNION DISTINCT
{"label": "Dst2ndAS", "detail": "column name", "quoted": false},
{"label": "Dst3rdAS", "detail": "column name", "quoted": false},
{"label": "DstAS", "detail": "column name", "quoted": false},
{"label": "DstASPath", "detail": "column name", "quoted": false},
{"label": "DstAddr", "detail": "column name", "quoted": false},
{"label": "DstCountry", "detail": "column name", "quoted": false},
{"label": "DstNetName", "detail": "column name", "quoted": false},
@@ -198,6 +200,23 @@ UNION DISTINCT
{"label": "AS36987", "detail": "Google Kenya", "quoted": false},
{"label": "AS41264", "detail": "Google Switzerland", "quoted": false},
}},
}, {
URL: "/api/v0/console/filter/complete",
StatusCode: 200,
JSONInput: gin.H{"what": "value", "column": "dstASpath", "prefix": "goog"},
JSONOutput: gin.H{"completions": []gin.H{
{"label": "AS15169", "detail": "Google", "quoted": false},
{"label": "AS16550", "detail": "Google Private Cloud", "quoted": false},
{"label": "AS16591", "detail": "Google Fiber", "quoted": false},
{"label": "AS19527", "detail": "Google", "quoted": false},
{"label": "AS26910", "detail": "GOOGLE-CLOUD-2", "quoted": false},
{"label": "AS36040", "detail": "Google", "quoted": false},
{"label": "AS36384", "detail": "Google", "quoted": false},
{"label": "AS36385", "detail": "Google IT", "quoted": false},
{"label": "AS36492", "detail": "Google", "quoted": false},
{"label": "AS36987", "detail": "Google Kenya", "quoted": false},
{"label": "AS41264", "detail": "Google Switzerland", "quoted": false},
}},
}, {
URL: "/api/v0/console/filter/complete",
StatusCode: 200,