]> git.feebdaed.xyz Git - 0xmirror/cilium.git/commitdiff
hubble: Add VNI to flow `tunnel` field
authorFabian Fischer <fabian.fischer@isovalent.com>
Wed, 17 Dec 2025 07:53:59 +0000 (08:53 +0100)
committerRobin Hahling <sherwood51@gmail.com>
Mon, 22 Dec 2025 11:55:07 +0000 (11:55 +0000)
In hubble flows, we already provide information on the used
encapsulation protocol in the `tunnel` field. It does, however, not
include any information on the used VNI.

For Cilium the VNI should generally always be equal to the source
identity. But including it can help with debugging issues, when we
get traffic from an unexpected VNI.

Signed-off-by: Fabian Fischer <fabian.fischer@isovalent.com>
api/v1/flow/README.md
api/v1/flow/flow.pb.go
api/v1/flow/flow.proto
pkg/hubble/parser/threefour/parser.go
pkg/hubble/parser/threefour/parser_test.go

index eda9b71e5cecf3fb337402d7a106d4a7de3b8cbf..ebbdddbb45ed095a1c2ee14748c676c8202cb651 100644 (file)
@@ -902,6 +902,7 @@ TraceParent identifies the incoming request in a tracing system.
 | protocol | [Tunnel.Protocol](#flow-Tunnel-Protocol) |  |  |
 | IP | [IP](#flow-IP) |  |  |
 | l4 | [Layer4](#flow-Layer4) |  |  |
+| vni | [uint32](#uint32) |  |  |
 
 
 
index 1b6cefd3f1f5ceee911c79d7abbffbb14ac4de62..4ef3db5975be473d9e3c2ddaeec0c379990e11d7 100644 (file)
@@ -3165,6 +3165,7 @@ type Tunnel struct {
        Protocol      Tunnel_Protocol        `protobuf:"varint,1,opt,name=protocol,proto3,enum=flow.Tunnel_Protocol" json:"protocol,omitempty"`
        IP            *IP                    `protobuf:"bytes,2,opt,name=IP,proto3" json:"IP,omitempty"`
        L4            *Layer4                `protobuf:"bytes,3,opt,name=l4,proto3" json:"l4,omitempty"`
+       Vni           uint32                 `protobuf:"varint,4,opt,name=vni,proto3" json:"vni,omitempty"`
        unknownFields protoimpl.UnknownFields
        sizeCache     protoimpl.SizeCache
 }
@@ -3220,6 +3221,13 @@ func (x *Tunnel) GetL4() *Layer4 {
        return nil
 }
 
+func (x *Tunnel) GetVni() uint32 {
+       if x != nil {
+               return x.Vni
+       }
+       return 0
+}
+
 type Policy struct {
        state         protoimpl.MessageState `protogen:"open.v1"`
        Name          string                 `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
@@ -5573,11 +5581,12 @@ const file_flow_flow_proto_rawDesc = "" +
        "\bpriority\x18\x03 \x01(\rR\bpriority\"?\n" +
        "\x04IGMP\x12\x12\n" +
        "\x04type\x18\x01 \x01(\rR\x04type\x12#\n" +
-       "\rgroup_address\x18\x02 \x01(\tR\fgroupAddress\"\xa3\x01\n" +
+       "\rgroup_address\x18\x02 \x01(\tR\fgroupAddress\"\xb5\x01\n" +
        "\x06Tunnel\x121\n" +
        "\bprotocol\x18\x01 \x01(\x0e2\x15.flow.Tunnel.ProtocolR\bprotocol\x12\x18\n" +
        "\x02IP\x18\x02 \x01(\v2\b.flow.IPR\x02IP\x12\x1c\n" +
-       "\x02l4\x18\x03 \x01(\v2\f.flow.Layer4R\x02l4\".\n" +
+       "\x02l4\x18\x03 \x01(\v2\f.flow.Layer4R\x02l4\x12\x10\n" +
+       "\x03vni\x18\x04 \x01(\rR\x03vni\".\n" +
        "\bProtocol\x12\v\n" +
        "\aUNKNOWN\x10\x00\x12\t\n" +
        "\x05VXLAN\x10\x01\x12\n" +
index 11f38080af1b1bbaf90818cb2b1b7e0cc1476715..c1219346caa4a70b34198fe7cb291b46ba194a1b 100644 (file)
@@ -396,6 +396,7 @@ message Tunnel {
     Protocol protocol = 1;
     IP IP = 2;
     Layer4 l4 = 3;
+    uint32 vni = 4;
 }
 
 enum Verdict {
index c9cb8176498ea29f21124a7e0400ece9aaae54ff..23eec78e6e56b92d781fb7e425f158350ab3390a 100644 (file)
@@ -408,9 +408,9 @@ func (d *packetDecoder) DecodePacket(payload []byte, decoded *pb.Flow, isL3Devic
        // Expect VXLAN/Geneve overlay as first overlay layer, if not we bail out.
        switch d.overlay.Layers[0] {
        case layers.LayerTypeVXLAN:
-               decoded.Tunnel = &pb.Tunnel{Protocol: pb.Tunnel_VXLAN, IP: decoded.IP, L4: decoded.L4}
+               decoded.Tunnel = &pb.Tunnel{Protocol: pb.Tunnel_VXLAN, IP: decoded.IP, L4: decoded.L4, Vni: d.overlay.VXLAN.VNI}
        case layers.LayerTypeGeneve:
-               decoded.Tunnel = &pb.Tunnel{Protocol: pb.Tunnel_GENEVE, IP: decoded.IP, L4: decoded.L4}
+               decoded.Tunnel = &pb.Tunnel{Protocol: pb.Tunnel_GENEVE, IP: decoded.IP, L4: decoded.L4, Vni: d.overlay.Geneve.VNI}
        default:
                return
        }
index 5680139b5b86273bcb709d6ed6da3043b2b5a163..029401b0c56a1eb7f59651c2892c4bf5090add74 100644 (file)
@@ -146,6 +146,7 @@ func TestL34DecodeVXLANOverlay(t *testing.T) {
 
        // Check tunnel containing the underlay info.
        assert.Equal(t, flowpb.Tunnel_VXLAN, f.GetTunnel().GetProtocol())
+       assert.Equal(t, uint32(2), f.GetTunnel().GetVni())
        assert.Equal(t, "192.168.1.1", f.GetTunnel().GetIP().GetSource())
        assert.Equal(t, "192.168.1.2", f.GetTunnel().GetIP().GetDestination())
        assert.Equal(t, uint32(defaults.TunnelPortVXLAN), f.GetTunnel().GetL4().GetUDP().GetSourcePort())
@@ -218,6 +219,7 @@ func TestL34DecodeGeneveOverlay(t *testing.T) {
 
        // Check tunnel containing the underlay info.
        assert.Equal(t, flowpb.Tunnel_GENEVE, f.GetTunnel().GetProtocol())
+       assert.Equal(t, uint32(2), f.GetTunnel().GetVni())
        assert.Equal(t, "192.168.1.1", f.GetTunnel().GetIP().GetSource())
        assert.Equal(t, "192.168.1.2", f.GetTunnel().GetIP().GetDestination())
        assert.Equal(t, uint32(defaults.TunnelPortGeneve), f.GetTunnel().GetL4().GetUDP().GetSourcePort())