From 698808e429e6f6cf609d6e9e0b3d88e2ff95fe73 Mon Sep 17 00:00:00 2001 From: stanislav-chlebec <32060603+stanislav-chlebec@users.noreply.github.com> Date: Tue, 16 Jul 2019 13:09:57 +0200 Subject: [PATCH 01/10] added memif interface test to tests/integration (#1412) Signed-off-by: Stanislav Chlebec --- tests/integration/vpp/001_basic_test.go | 35 +++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/integration/vpp/001_basic_test.go b/tests/integration/vpp/001_basic_test.go index 4676fb1055..0a6830b81e 100644 --- a/tests/integration/vpp/001_basic_test.go +++ b/tests/integration/vpp/001_basic_test.go @@ -59,6 +59,41 @@ func TestLoopbackInterface(t *testing.T) { } } +func TestMemifInterface(t *testing.T) { + ctx := setupVPP(t) + defer ctx.teardownVPP() + + h := ifplugin_vppcalls.CompatibleInterfaceVppHandler(ctx.Chan, logrus.NewLogger("test")) + + index, err := h.AddMemifInterface("memif1", &vpp_interfaces.MemifLink{ + Id: 1, + Mode: vpp_interfaces.MemifLink_IP, + Secret: "secret", + Master: true, + }, 0 ) + + if err != nil { + t.Fatalf("creating memif interface failed: %v", err) + } + t.Logf("memif index: %+v", index) + + ifaces, err := h.DumpInterfaces() + if err != nil { + t.Fatalf("dumping interfaces failed: %v", err) + } + iface, ok := ifaces[index] + if !ok { + t.Fatalf("Memif interface not found in dump") + } + t.Logf("interface: %+v", iface.Interface) + if iface.Interface.Name != "memif1" { + t.Fatalf("expected interface name to be memif1, got %v", iface.Interface.Name) + } + if iface.Interface.Type != vpp_interfaces.Interface_MEMIF { + t.Fatalf("expected interface type to be memif, got %v", iface.Interface.Type) + } +} + func TestRoutes(t *testing.T) { ctx := setupVPP(t) defer ctx.teardownVPP() From 9313c984c138a9930d4c3eea980d8e20b7bd77fa Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Wed, 17 Jul 2019 06:47:06 +0200 Subject: [PATCH 02/10] Update VPP to 19.08-rc0.666-g9082b43dd (#1413) * Update VPP to 19.08-rc0.666-g9082b43dd Signed-off-by: Ondrej Fabry * Update VPP to 19.08-rc0.673-ga2e4451db Signed-off-by: Ondrej Fabry --- plugins/vpp/binapi/vpp1908/abf/abf.ba.go | 167 +++++++++++- plugins/vpp/binapi/vpp1908/ip/ip.ba.go | 167 +++++++++++- plugins/vpp/binapi/vpp1908/ipsec/ipsec.ba.go | 167 +++++++++++- plugins/vpp/binapi/vpp1908/l2/l2.ba.go | 167 +++++++++++- plugins/vpp/binapi/vpp1908/nat/nat.ba.go | 167 +++++++++++- plugins/vpp/binapi/vpp1908/punt/punt.ba.go | 173 +++++++++++-- plugins/vpp/binapi/vpp1908/vpe/vpe.ba.go | 257 ++++++++++++++++++- scripts/genbinapi.sh | 2 +- scripts/install_protobuf.sh | 0 vpp.env | 2 +- 10 files changed, 1177 insertions(+), 92 deletions(-) mode change 100644 => 100755 scripts/install_protobuf.sh diff --git a/plugins/vpp/binapi/vpp1908/abf/abf.ba.go b/plugins/vpp/binapi/vpp1908/abf/abf.ba.go index af524a4b68..cd23e8d82e 100644 --- a/plugins/vpp/binapi/vpp1908/abf/abf.ba.go +++ b/plugins/vpp/binapi/vpp1908/abf/abf.ba.go @@ -5,7 +5,7 @@ Package abf is a generated VPP binary API for 'abf' module. It consists of: - 5 enums + 7 enums 2 aliases 10 types 1 union @@ -29,7 +29,7 @@ const ( // APIVersion is the API version of this module. APIVersion = "1.0.0" // VersionCrc is the CRC of this module. - VersionCrc = 0x25b8fffd + VersionCrc = 0x89235b51 ) // AddressFamily represents VPP binary API enum 'address_family'. @@ -175,28 +175,167 @@ func (x FibPathType) String() string { return strconv.Itoa(int(x)) } +// IPDscp represents VPP binary API enum 'ip_dscp'. +type IPDscp uint8 + +const ( + IP_API_DSCP_CS0 IPDscp = 0 + IP_API_DSCP_CS1 IPDscp = 8 + IP_API_DSCP_AF11 IPDscp = 10 + IP_API_DSCP_AF12 IPDscp = 12 + IP_API_DSCP_AF13 IPDscp = 14 + IP_API_DSCP_CS2 IPDscp = 16 + IP_API_DSCP_AF21 IPDscp = 18 + IP_API_DSCP_AF22 IPDscp = 20 + IP_API_DSCP_AF23 IPDscp = 22 + IP_API_DSCP_CS3 IPDscp = 24 + IP_API_DSCP_AF31 IPDscp = 26 + IP_API_DSCP_AF32 IPDscp = 28 + IP_API_DSCP_AF33 IPDscp = 30 + IP_API_DSCP_CS4 IPDscp = 32 + IP_API_DSCP_AF41 IPDscp = 34 + IP_API_DSCP_AF42 IPDscp = 36 + IP_API_DSCP_AF43 IPDscp = 38 + IP_API_DSCP_CS5 IPDscp = 40 + IP_API_DSCP_EF IPDscp = 46 + IP_API_DSCP_CS6 IPDscp = 48 + IP_API_DSCP_CS7 IPDscp = 50 +) + +var IPDscp_name = map[uint8]string{ + 0: "IP_API_DSCP_CS0", + 8: "IP_API_DSCP_CS1", + 10: "IP_API_DSCP_AF11", + 12: "IP_API_DSCP_AF12", + 14: "IP_API_DSCP_AF13", + 16: "IP_API_DSCP_CS2", + 18: "IP_API_DSCP_AF21", + 20: "IP_API_DSCP_AF22", + 22: "IP_API_DSCP_AF23", + 24: "IP_API_DSCP_CS3", + 26: "IP_API_DSCP_AF31", + 28: "IP_API_DSCP_AF32", + 30: "IP_API_DSCP_AF33", + 32: "IP_API_DSCP_CS4", + 34: "IP_API_DSCP_AF41", + 36: "IP_API_DSCP_AF42", + 38: "IP_API_DSCP_AF43", + 40: "IP_API_DSCP_CS5", + 46: "IP_API_DSCP_EF", + 48: "IP_API_DSCP_CS6", + 50: "IP_API_DSCP_CS7", +} + +var IPDscp_value = map[string]uint8{ + "IP_API_DSCP_CS0": 0, + "IP_API_DSCP_CS1": 8, + "IP_API_DSCP_AF11": 10, + "IP_API_DSCP_AF12": 12, + "IP_API_DSCP_AF13": 14, + "IP_API_DSCP_CS2": 16, + "IP_API_DSCP_AF21": 18, + "IP_API_DSCP_AF22": 20, + "IP_API_DSCP_AF23": 22, + "IP_API_DSCP_CS3": 24, + "IP_API_DSCP_AF31": 26, + "IP_API_DSCP_AF32": 28, + "IP_API_DSCP_AF33": 30, + "IP_API_DSCP_CS4": 32, + "IP_API_DSCP_AF41": 34, + "IP_API_DSCP_AF42": 36, + "IP_API_DSCP_AF43": 38, + "IP_API_DSCP_CS5": 40, + "IP_API_DSCP_EF": 46, + "IP_API_DSCP_CS6": 48, + "IP_API_DSCP_CS7": 50, +} + +func (x IPDscp) String() string { + s, ok := IPDscp_name[uint8(x)] + if ok { + return s + } + return strconv.Itoa(int(x)) +} + +// IPEcn represents VPP binary API enum 'ip_ecn'. +type IPEcn uint8 + +const ( + IP_API_ECN_NONE IPEcn = 0 + IP_API_ECN_ECT0 IPEcn = 1 + IP_API_ECN_ECT1 IPEcn = 2 + IP_API_ECN_CE IPEcn = 3 +) + +var IPEcn_name = map[uint8]string{ + 0: "IP_API_ECN_NONE", + 1: "IP_API_ECN_ECT0", + 2: "IP_API_ECN_ECT1", + 3: "IP_API_ECN_CE", +} + +var IPEcn_value = map[string]uint8{ + "IP_API_ECN_NONE": 0, + "IP_API_ECN_ECT0": 1, + "IP_API_ECN_ECT1": 2, + "IP_API_ECN_CE": 3, +} + +func (x IPEcn) String() string { + s, ok := IPEcn_name[uint8(x)] + if ok { + return s + } + return strconv.Itoa(int(x)) +} + // IPProto represents VPP binary API enum 'ip_proto'. type IPProto uint32 const ( - IP_API_PROTO_TCP IPProto = 6 - IP_API_PROTO_UDP IPProto = 17 - IP_API_PROTO_EIGRP IPProto = 88 - IP_API_PROTO_OSPF IPProto = 89 + IP_API_PROTO_HOPOPT IPProto = 0 + IP_API_PROTO_ICMP IPProto = 1 + IP_API_PROTO_IGMP IPProto = 2 + IP_API_PROTO_TCP IPProto = 6 + IP_API_PROTO_UDP IPProto = 17 + IP_API_PROTO_GRE IPProto = 47 + IP_API_PROTO_AH IPProto = 50 + IP_API_PROTO_ESP IPProto = 51 + IP_API_PROTO_EIGRP IPProto = 88 + IP_API_PROTO_OSPF IPProto = 89 + IP_API_PROTO_SCTP IPProto = 132 + IP_API_PROTO_RESERVED IPProto = 255 ) var IPProto_name = map[uint32]string{ - 6: "IP_API_PROTO_TCP", - 17: "IP_API_PROTO_UDP", - 88: "IP_API_PROTO_EIGRP", - 89: "IP_API_PROTO_OSPF", + 0: "IP_API_PROTO_HOPOPT", + 1: "IP_API_PROTO_ICMP", + 2: "IP_API_PROTO_IGMP", + 6: "IP_API_PROTO_TCP", + 17: "IP_API_PROTO_UDP", + 47: "IP_API_PROTO_GRE", + 50: "IP_API_PROTO_AH", + 51: "IP_API_PROTO_ESP", + 88: "IP_API_PROTO_EIGRP", + 89: "IP_API_PROTO_OSPF", + 132: "IP_API_PROTO_SCTP", + 255: "IP_API_PROTO_RESERVED", } var IPProto_value = map[string]uint32{ - "IP_API_PROTO_TCP": 6, - "IP_API_PROTO_UDP": 17, - "IP_API_PROTO_EIGRP": 88, - "IP_API_PROTO_OSPF": 89, + "IP_API_PROTO_HOPOPT": 0, + "IP_API_PROTO_ICMP": 1, + "IP_API_PROTO_IGMP": 2, + "IP_API_PROTO_TCP": 6, + "IP_API_PROTO_UDP": 17, + "IP_API_PROTO_GRE": 47, + "IP_API_PROTO_AH": 50, + "IP_API_PROTO_ESP": 51, + "IP_API_PROTO_EIGRP": 88, + "IP_API_PROTO_OSPF": 89, + "IP_API_PROTO_SCTP": 132, + "IP_API_PROTO_RESERVED": 255, } func (x IPProto) String() string { diff --git a/plugins/vpp/binapi/vpp1908/ip/ip.ba.go b/plugins/vpp/binapi/vpp1908/ip/ip.ba.go index 3426f811ba..246c2f0d76 100644 --- a/plugins/vpp/binapi/vpp1908/ip/ip.ba.go +++ b/plugins/vpp/binapi/vpp1908/ip/ip.ba.go @@ -5,7 +5,7 @@ Package ip is a generated VPP binary API for 'ip' module. It consists of: - 7 enums + 9 enums 3 aliases 16 types 1 union @@ -29,7 +29,7 @@ const ( // APIVersion is the API version of this module. APIVersion = "3.0.0" // VersionCrc is the CRC of this module. - VersionCrc = 0x66000d59 + VersionCrc = 0xc28cff0d ) // AddressFamily represents VPP binary API enum 'address_family'. @@ -175,6 +175,121 @@ func (x FibPathType) String() string { return strconv.Itoa(int(x)) } +// IPDscp represents VPP binary API enum 'ip_dscp'. +type IPDscp uint8 + +const ( + IP_API_DSCP_CS0 IPDscp = 0 + IP_API_DSCP_CS1 IPDscp = 8 + IP_API_DSCP_AF11 IPDscp = 10 + IP_API_DSCP_AF12 IPDscp = 12 + IP_API_DSCP_AF13 IPDscp = 14 + IP_API_DSCP_CS2 IPDscp = 16 + IP_API_DSCP_AF21 IPDscp = 18 + IP_API_DSCP_AF22 IPDscp = 20 + IP_API_DSCP_AF23 IPDscp = 22 + IP_API_DSCP_CS3 IPDscp = 24 + IP_API_DSCP_AF31 IPDscp = 26 + IP_API_DSCP_AF32 IPDscp = 28 + IP_API_DSCP_AF33 IPDscp = 30 + IP_API_DSCP_CS4 IPDscp = 32 + IP_API_DSCP_AF41 IPDscp = 34 + IP_API_DSCP_AF42 IPDscp = 36 + IP_API_DSCP_AF43 IPDscp = 38 + IP_API_DSCP_CS5 IPDscp = 40 + IP_API_DSCP_EF IPDscp = 46 + IP_API_DSCP_CS6 IPDscp = 48 + IP_API_DSCP_CS7 IPDscp = 50 +) + +var IPDscp_name = map[uint8]string{ + 0: "IP_API_DSCP_CS0", + 8: "IP_API_DSCP_CS1", + 10: "IP_API_DSCP_AF11", + 12: "IP_API_DSCP_AF12", + 14: "IP_API_DSCP_AF13", + 16: "IP_API_DSCP_CS2", + 18: "IP_API_DSCP_AF21", + 20: "IP_API_DSCP_AF22", + 22: "IP_API_DSCP_AF23", + 24: "IP_API_DSCP_CS3", + 26: "IP_API_DSCP_AF31", + 28: "IP_API_DSCP_AF32", + 30: "IP_API_DSCP_AF33", + 32: "IP_API_DSCP_CS4", + 34: "IP_API_DSCP_AF41", + 36: "IP_API_DSCP_AF42", + 38: "IP_API_DSCP_AF43", + 40: "IP_API_DSCP_CS5", + 46: "IP_API_DSCP_EF", + 48: "IP_API_DSCP_CS6", + 50: "IP_API_DSCP_CS7", +} + +var IPDscp_value = map[string]uint8{ + "IP_API_DSCP_CS0": 0, + "IP_API_DSCP_CS1": 8, + "IP_API_DSCP_AF11": 10, + "IP_API_DSCP_AF12": 12, + "IP_API_DSCP_AF13": 14, + "IP_API_DSCP_CS2": 16, + "IP_API_DSCP_AF21": 18, + "IP_API_DSCP_AF22": 20, + "IP_API_DSCP_AF23": 22, + "IP_API_DSCP_CS3": 24, + "IP_API_DSCP_AF31": 26, + "IP_API_DSCP_AF32": 28, + "IP_API_DSCP_AF33": 30, + "IP_API_DSCP_CS4": 32, + "IP_API_DSCP_AF41": 34, + "IP_API_DSCP_AF42": 36, + "IP_API_DSCP_AF43": 38, + "IP_API_DSCP_CS5": 40, + "IP_API_DSCP_EF": 46, + "IP_API_DSCP_CS6": 48, + "IP_API_DSCP_CS7": 50, +} + +func (x IPDscp) String() string { + s, ok := IPDscp_name[uint8(x)] + if ok { + return s + } + return strconv.Itoa(int(x)) +} + +// IPEcn represents VPP binary API enum 'ip_ecn'. +type IPEcn uint8 + +const ( + IP_API_ECN_NONE IPEcn = 0 + IP_API_ECN_ECT0 IPEcn = 1 + IP_API_ECN_ECT1 IPEcn = 2 + IP_API_ECN_CE IPEcn = 3 +) + +var IPEcn_name = map[uint8]string{ + 0: "IP_API_ECN_NONE", + 1: "IP_API_ECN_ECT0", + 2: "IP_API_ECN_ECT1", + 3: "IP_API_ECN_CE", +} + +var IPEcn_value = map[string]uint8{ + "IP_API_ECN_NONE": 0, + "IP_API_ECN_ECT0": 1, + "IP_API_ECN_ECT1": 2, + "IP_API_ECN_CE": 3, +} + +func (x IPEcn) String() string { + s, ok := IPEcn_name[uint8(x)] + if ok { + return s + } + return strconv.Itoa(int(x)) +} + // IPNeighborFlags represents VPP binary API enum 'ip_neighbor_flags'. type IPNeighborFlags uint32 @@ -208,24 +323,48 @@ func (x IPNeighborFlags) String() string { type IPProto uint32 const ( - IP_API_PROTO_TCP IPProto = 6 - IP_API_PROTO_UDP IPProto = 17 - IP_API_PROTO_EIGRP IPProto = 88 - IP_API_PROTO_OSPF IPProto = 89 + IP_API_PROTO_HOPOPT IPProto = 0 + IP_API_PROTO_ICMP IPProto = 1 + IP_API_PROTO_IGMP IPProto = 2 + IP_API_PROTO_TCP IPProto = 6 + IP_API_PROTO_UDP IPProto = 17 + IP_API_PROTO_GRE IPProto = 47 + IP_API_PROTO_AH IPProto = 50 + IP_API_PROTO_ESP IPProto = 51 + IP_API_PROTO_EIGRP IPProto = 88 + IP_API_PROTO_OSPF IPProto = 89 + IP_API_PROTO_SCTP IPProto = 132 + IP_API_PROTO_RESERVED IPProto = 255 ) var IPProto_name = map[uint32]string{ - 6: "IP_API_PROTO_TCP", - 17: "IP_API_PROTO_UDP", - 88: "IP_API_PROTO_EIGRP", - 89: "IP_API_PROTO_OSPF", + 0: "IP_API_PROTO_HOPOPT", + 1: "IP_API_PROTO_ICMP", + 2: "IP_API_PROTO_IGMP", + 6: "IP_API_PROTO_TCP", + 17: "IP_API_PROTO_UDP", + 47: "IP_API_PROTO_GRE", + 50: "IP_API_PROTO_AH", + 51: "IP_API_PROTO_ESP", + 88: "IP_API_PROTO_EIGRP", + 89: "IP_API_PROTO_OSPF", + 132: "IP_API_PROTO_SCTP", + 255: "IP_API_PROTO_RESERVED", } var IPProto_value = map[string]uint32{ - "IP_API_PROTO_TCP": 6, - "IP_API_PROTO_UDP": 17, - "IP_API_PROTO_EIGRP": 88, - "IP_API_PROTO_OSPF": 89, + "IP_API_PROTO_HOPOPT": 0, + "IP_API_PROTO_ICMP": 1, + "IP_API_PROTO_IGMP": 2, + "IP_API_PROTO_TCP": 6, + "IP_API_PROTO_UDP": 17, + "IP_API_PROTO_GRE": 47, + "IP_API_PROTO_AH": 50, + "IP_API_PROTO_ESP": 51, + "IP_API_PROTO_EIGRP": 88, + "IP_API_PROTO_OSPF": 89, + "IP_API_PROTO_SCTP": 132, + "IP_API_PROTO_RESERVED": 255, } func (x IPProto) String() string { diff --git a/plugins/vpp/binapi/vpp1908/ipsec/ipsec.ba.go b/plugins/vpp/binapi/vpp1908/ipsec/ipsec.ba.go index 55af4dd7ac..dc69c8a6f4 100644 --- a/plugins/vpp/binapi/vpp1908/ipsec/ipsec.ba.go +++ b/plugins/vpp/binapi/vpp1908/ipsec/ipsec.ba.go @@ -5,7 +5,7 @@ Package ipsec is a generated VPP binary API for 'ipsec' module. It consists of: - 7 enums + 9 enums 3 aliases 9 types 1 union @@ -29,7 +29,7 @@ const ( // APIVersion is the API version of this module. APIVersion = "3.0.0" // VersionCrc is the CRC of this module. - VersionCrc = 0xfc13e31d + VersionCrc = 0xd2452344 ) // AddressFamily represents VPP binary API enum 'address_family'. @@ -58,28 +58,167 @@ func (x AddressFamily) String() string { return strconv.Itoa(int(x)) } +// IPDscp represents VPP binary API enum 'ip_dscp'. +type IPDscp uint8 + +const ( + IP_API_DSCP_CS0 IPDscp = 0 + IP_API_DSCP_CS1 IPDscp = 8 + IP_API_DSCP_AF11 IPDscp = 10 + IP_API_DSCP_AF12 IPDscp = 12 + IP_API_DSCP_AF13 IPDscp = 14 + IP_API_DSCP_CS2 IPDscp = 16 + IP_API_DSCP_AF21 IPDscp = 18 + IP_API_DSCP_AF22 IPDscp = 20 + IP_API_DSCP_AF23 IPDscp = 22 + IP_API_DSCP_CS3 IPDscp = 24 + IP_API_DSCP_AF31 IPDscp = 26 + IP_API_DSCP_AF32 IPDscp = 28 + IP_API_DSCP_AF33 IPDscp = 30 + IP_API_DSCP_CS4 IPDscp = 32 + IP_API_DSCP_AF41 IPDscp = 34 + IP_API_DSCP_AF42 IPDscp = 36 + IP_API_DSCP_AF43 IPDscp = 38 + IP_API_DSCP_CS5 IPDscp = 40 + IP_API_DSCP_EF IPDscp = 46 + IP_API_DSCP_CS6 IPDscp = 48 + IP_API_DSCP_CS7 IPDscp = 50 +) + +var IPDscp_name = map[uint8]string{ + 0: "IP_API_DSCP_CS0", + 8: "IP_API_DSCP_CS1", + 10: "IP_API_DSCP_AF11", + 12: "IP_API_DSCP_AF12", + 14: "IP_API_DSCP_AF13", + 16: "IP_API_DSCP_CS2", + 18: "IP_API_DSCP_AF21", + 20: "IP_API_DSCP_AF22", + 22: "IP_API_DSCP_AF23", + 24: "IP_API_DSCP_CS3", + 26: "IP_API_DSCP_AF31", + 28: "IP_API_DSCP_AF32", + 30: "IP_API_DSCP_AF33", + 32: "IP_API_DSCP_CS4", + 34: "IP_API_DSCP_AF41", + 36: "IP_API_DSCP_AF42", + 38: "IP_API_DSCP_AF43", + 40: "IP_API_DSCP_CS5", + 46: "IP_API_DSCP_EF", + 48: "IP_API_DSCP_CS6", + 50: "IP_API_DSCP_CS7", +} + +var IPDscp_value = map[string]uint8{ + "IP_API_DSCP_CS0": 0, + "IP_API_DSCP_CS1": 8, + "IP_API_DSCP_AF11": 10, + "IP_API_DSCP_AF12": 12, + "IP_API_DSCP_AF13": 14, + "IP_API_DSCP_CS2": 16, + "IP_API_DSCP_AF21": 18, + "IP_API_DSCP_AF22": 20, + "IP_API_DSCP_AF23": 22, + "IP_API_DSCP_CS3": 24, + "IP_API_DSCP_AF31": 26, + "IP_API_DSCP_AF32": 28, + "IP_API_DSCP_AF33": 30, + "IP_API_DSCP_CS4": 32, + "IP_API_DSCP_AF41": 34, + "IP_API_DSCP_AF42": 36, + "IP_API_DSCP_AF43": 38, + "IP_API_DSCP_CS5": 40, + "IP_API_DSCP_EF": 46, + "IP_API_DSCP_CS6": 48, + "IP_API_DSCP_CS7": 50, +} + +func (x IPDscp) String() string { + s, ok := IPDscp_name[uint8(x)] + if ok { + return s + } + return strconv.Itoa(int(x)) +} + +// IPEcn represents VPP binary API enum 'ip_ecn'. +type IPEcn uint8 + +const ( + IP_API_ECN_NONE IPEcn = 0 + IP_API_ECN_ECT0 IPEcn = 1 + IP_API_ECN_ECT1 IPEcn = 2 + IP_API_ECN_CE IPEcn = 3 +) + +var IPEcn_name = map[uint8]string{ + 0: "IP_API_ECN_NONE", + 1: "IP_API_ECN_ECT0", + 2: "IP_API_ECN_ECT1", + 3: "IP_API_ECN_CE", +} + +var IPEcn_value = map[string]uint8{ + "IP_API_ECN_NONE": 0, + "IP_API_ECN_ECT0": 1, + "IP_API_ECN_ECT1": 2, + "IP_API_ECN_CE": 3, +} + +func (x IPEcn) String() string { + s, ok := IPEcn_name[uint8(x)] + if ok { + return s + } + return strconv.Itoa(int(x)) +} + // IPProto represents VPP binary API enum 'ip_proto'. type IPProto uint32 const ( - IP_API_PROTO_TCP IPProto = 6 - IP_API_PROTO_UDP IPProto = 17 - IP_API_PROTO_EIGRP IPProto = 88 - IP_API_PROTO_OSPF IPProto = 89 + IP_API_PROTO_HOPOPT IPProto = 0 + IP_API_PROTO_ICMP IPProto = 1 + IP_API_PROTO_IGMP IPProto = 2 + IP_API_PROTO_TCP IPProto = 6 + IP_API_PROTO_UDP IPProto = 17 + IP_API_PROTO_GRE IPProto = 47 + IP_API_PROTO_AH IPProto = 50 + IP_API_PROTO_ESP IPProto = 51 + IP_API_PROTO_EIGRP IPProto = 88 + IP_API_PROTO_OSPF IPProto = 89 + IP_API_PROTO_SCTP IPProto = 132 + IP_API_PROTO_RESERVED IPProto = 255 ) var IPProto_name = map[uint32]string{ - 6: "IP_API_PROTO_TCP", - 17: "IP_API_PROTO_UDP", - 88: "IP_API_PROTO_EIGRP", - 89: "IP_API_PROTO_OSPF", + 0: "IP_API_PROTO_HOPOPT", + 1: "IP_API_PROTO_ICMP", + 2: "IP_API_PROTO_IGMP", + 6: "IP_API_PROTO_TCP", + 17: "IP_API_PROTO_UDP", + 47: "IP_API_PROTO_GRE", + 50: "IP_API_PROTO_AH", + 51: "IP_API_PROTO_ESP", + 88: "IP_API_PROTO_EIGRP", + 89: "IP_API_PROTO_OSPF", + 132: "IP_API_PROTO_SCTP", + 255: "IP_API_PROTO_RESERVED", } var IPProto_value = map[string]uint32{ - "IP_API_PROTO_TCP": 6, - "IP_API_PROTO_UDP": 17, - "IP_API_PROTO_EIGRP": 88, - "IP_API_PROTO_OSPF": 89, + "IP_API_PROTO_HOPOPT": 0, + "IP_API_PROTO_ICMP": 1, + "IP_API_PROTO_IGMP": 2, + "IP_API_PROTO_TCP": 6, + "IP_API_PROTO_UDP": 17, + "IP_API_PROTO_GRE": 47, + "IP_API_PROTO_AH": 50, + "IP_API_PROTO_ESP": 51, + "IP_API_PROTO_EIGRP": 88, + "IP_API_PROTO_OSPF": 89, + "IP_API_PROTO_SCTP": 132, + "IP_API_PROTO_RESERVED": 255, } func (x IPProto) String() string { diff --git a/plugins/vpp/binapi/vpp1908/l2/l2.ba.go b/plugins/vpp/binapi/vpp1908/l2/l2.ba.go index 0cfa914515..39ec8f5f26 100644 --- a/plugins/vpp/binapi/vpp1908/l2/l2.ba.go +++ b/plugins/vpp/binapi/vpp1908/l2/l2.ba.go @@ -5,7 +5,7 @@ Package l2 is a generated VPP binary API for 'l2' module. It consists of: - 4 enums + 6 enums 3 aliases 8 types 1 union @@ -29,7 +29,7 @@ const ( // APIVersion is the API version of this module. APIVersion = "2.2.2" // VersionCrc is the CRC of this module. - VersionCrc = 0xbaafc7be + VersionCrc = 0x46c9d538 ) // AddressFamily represents VPP binary API enum 'address_family'. @@ -99,28 +99,167 @@ func (x BdFlags) String() string { return strconv.Itoa(int(x)) } +// IPDscp represents VPP binary API enum 'ip_dscp'. +type IPDscp uint8 + +const ( + IP_API_DSCP_CS0 IPDscp = 0 + IP_API_DSCP_CS1 IPDscp = 8 + IP_API_DSCP_AF11 IPDscp = 10 + IP_API_DSCP_AF12 IPDscp = 12 + IP_API_DSCP_AF13 IPDscp = 14 + IP_API_DSCP_CS2 IPDscp = 16 + IP_API_DSCP_AF21 IPDscp = 18 + IP_API_DSCP_AF22 IPDscp = 20 + IP_API_DSCP_AF23 IPDscp = 22 + IP_API_DSCP_CS3 IPDscp = 24 + IP_API_DSCP_AF31 IPDscp = 26 + IP_API_DSCP_AF32 IPDscp = 28 + IP_API_DSCP_AF33 IPDscp = 30 + IP_API_DSCP_CS4 IPDscp = 32 + IP_API_DSCP_AF41 IPDscp = 34 + IP_API_DSCP_AF42 IPDscp = 36 + IP_API_DSCP_AF43 IPDscp = 38 + IP_API_DSCP_CS5 IPDscp = 40 + IP_API_DSCP_EF IPDscp = 46 + IP_API_DSCP_CS6 IPDscp = 48 + IP_API_DSCP_CS7 IPDscp = 50 +) + +var IPDscp_name = map[uint8]string{ + 0: "IP_API_DSCP_CS0", + 8: "IP_API_DSCP_CS1", + 10: "IP_API_DSCP_AF11", + 12: "IP_API_DSCP_AF12", + 14: "IP_API_DSCP_AF13", + 16: "IP_API_DSCP_CS2", + 18: "IP_API_DSCP_AF21", + 20: "IP_API_DSCP_AF22", + 22: "IP_API_DSCP_AF23", + 24: "IP_API_DSCP_CS3", + 26: "IP_API_DSCP_AF31", + 28: "IP_API_DSCP_AF32", + 30: "IP_API_DSCP_AF33", + 32: "IP_API_DSCP_CS4", + 34: "IP_API_DSCP_AF41", + 36: "IP_API_DSCP_AF42", + 38: "IP_API_DSCP_AF43", + 40: "IP_API_DSCP_CS5", + 46: "IP_API_DSCP_EF", + 48: "IP_API_DSCP_CS6", + 50: "IP_API_DSCP_CS7", +} + +var IPDscp_value = map[string]uint8{ + "IP_API_DSCP_CS0": 0, + "IP_API_DSCP_CS1": 8, + "IP_API_DSCP_AF11": 10, + "IP_API_DSCP_AF12": 12, + "IP_API_DSCP_AF13": 14, + "IP_API_DSCP_CS2": 16, + "IP_API_DSCP_AF21": 18, + "IP_API_DSCP_AF22": 20, + "IP_API_DSCP_AF23": 22, + "IP_API_DSCP_CS3": 24, + "IP_API_DSCP_AF31": 26, + "IP_API_DSCP_AF32": 28, + "IP_API_DSCP_AF33": 30, + "IP_API_DSCP_CS4": 32, + "IP_API_DSCP_AF41": 34, + "IP_API_DSCP_AF42": 36, + "IP_API_DSCP_AF43": 38, + "IP_API_DSCP_CS5": 40, + "IP_API_DSCP_EF": 46, + "IP_API_DSCP_CS6": 48, + "IP_API_DSCP_CS7": 50, +} + +func (x IPDscp) String() string { + s, ok := IPDscp_name[uint8(x)] + if ok { + return s + } + return strconv.Itoa(int(x)) +} + +// IPEcn represents VPP binary API enum 'ip_ecn'. +type IPEcn uint8 + +const ( + IP_API_ECN_NONE IPEcn = 0 + IP_API_ECN_ECT0 IPEcn = 1 + IP_API_ECN_ECT1 IPEcn = 2 + IP_API_ECN_CE IPEcn = 3 +) + +var IPEcn_name = map[uint8]string{ + 0: "IP_API_ECN_NONE", + 1: "IP_API_ECN_ECT0", + 2: "IP_API_ECN_ECT1", + 3: "IP_API_ECN_CE", +} + +var IPEcn_value = map[string]uint8{ + "IP_API_ECN_NONE": 0, + "IP_API_ECN_ECT0": 1, + "IP_API_ECN_ECT1": 2, + "IP_API_ECN_CE": 3, +} + +func (x IPEcn) String() string { + s, ok := IPEcn_name[uint8(x)] + if ok { + return s + } + return strconv.Itoa(int(x)) +} + // IPProto represents VPP binary API enum 'ip_proto'. type IPProto uint32 const ( - IP_API_PROTO_TCP IPProto = 6 - IP_API_PROTO_UDP IPProto = 17 - IP_API_PROTO_EIGRP IPProto = 88 - IP_API_PROTO_OSPF IPProto = 89 + IP_API_PROTO_HOPOPT IPProto = 0 + IP_API_PROTO_ICMP IPProto = 1 + IP_API_PROTO_IGMP IPProto = 2 + IP_API_PROTO_TCP IPProto = 6 + IP_API_PROTO_UDP IPProto = 17 + IP_API_PROTO_GRE IPProto = 47 + IP_API_PROTO_AH IPProto = 50 + IP_API_PROTO_ESP IPProto = 51 + IP_API_PROTO_EIGRP IPProto = 88 + IP_API_PROTO_OSPF IPProto = 89 + IP_API_PROTO_SCTP IPProto = 132 + IP_API_PROTO_RESERVED IPProto = 255 ) var IPProto_name = map[uint32]string{ - 6: "IP_API_PROTO_TCP", - 17: "IP_API_PROTO_UDP", - 88: "IP_API_PROTO_EIGRP", - 89: "IP_API_PROTO_OSPF", + 0: "IP_API_PROTO_HOPOPT", + 1: "IP_API_PROTO_ICMP", + 2: "IP_API_PROTO_IGMP", + 6: "IP_API_PROTO_TCP", + 17: "IP_API_PROTO_UDP", + 47: "IP_API_PROTO_GRE", + 50: "IP_API_PROTO_AH", + 51: "IP_API_PROTO_ESP", + 88: "IP_API_PROTO_EIGRP", + 89: "IP_API_PROTO_OSPF", + 132: "IP_API_PROTO_SCTP", + 255: "IP_API_PROTO_RESERVED", } var IPProto_value = map[string]uint32{ - "IP_API_PROTO_TCP": 6, - "IP_API_PROTO_UDP": 17, - "IP_API_PROTO_EIGRP": 88, - "IP_API_PROTO_OSPF": 89, + "IP_API_PROTO_HOPOPT": 0, + "IP_API_PROTO_ICMP": 1, + "IP_API_PROTO_IGMP": 2, + "IP_API_PROTO_TCP": 6, + "IP_API_PROTO_UDP": 17, + "IP_API_PROTO_GRE": 47, + "IP_API_PROTO_AH": 50, + "IP_API_PROTO_ESP": 51, + "IP_API_PROTO_EIGRP": 88, + "IP_API_PROTO_OSPF": 89, + "IP_API_PROTO_SCTP": 132, + "IP_API_PROTO_RESERVED": 255, } func (x IPProto) String() string { diff --git a/plugins/vpp/binapi/vpp1908/nat/nat.ba.go b/plugins/vpp/binapi/vpp1908/nat/nat.ba.go index 6e60fe7d59..de5f7393df 100644 --- a/plugins/vpp/binapi/vpp1908/nat/nat.ba.go +++ b/plugins/vpp/binapi/vpp1908/nat/nat.ba.go @@ -5,7 +5,7 @@ Package nat is a generated VPP binary API for 'nat' module. It consists of: - 3 enums + 5 enums 3 aliases 6 types 1 union @@ -29,7 +29,7 @@ const ( // APIVersion is the API version of this module. APIVersion = "5.0.0" // VersionCrc is the CRC of this module. - VersionCrc = 0x7cd9bbbc + VersionCrc = 0x68a1a63b ) // AddressFamily represents VPP binary API enum 'address_family'. @@ -58,28 +58,167 @@ func (x AddressFamily) String() string { return strconv.Itoa(int(x)) } +// IPDscp represents VPP binary API enum 'ip_dscp'. +type IPDscp uint8 + +const ( + IP_API_DSCP_CS0 IPDscp = 0 + IP_API_DSCP_CS1 IPDscp = 8 + IP_API_DSCP_AF11 IPDscp = 10 + IP_API_DSCP_AF12 IPDscp = 12 + IP_API_DSCP_AF13 IPDscp = 14 + IP_API_DSCP_CS2 IPDscp = 16 + IP_API_DSCP_AF21 IPDscp = 18 + IP_API_DSCP_AF22 IPDscp = 20 + IP_API_DSCP_AF23 IPDscp = 22 + IP_API_DSCP_CS3 IPDscp = 24 + IP_API_DSCP_AF31 IPDscp = 26 + IP_API_DSCP_AF32 IPDscp = 28 + IP_API_DSCP_AF33 IPDscp = 30 + IP_API_DSCP_CS4 IPDscp = 32 + IP_API_DSCP_AF41 IPDscp = 34 + IP_API_DSCP_AF42 IPDscp = 36 + IP_API_DSCP_AF43 IPDscp = 38 + IP_API_DSCP_CS5 IPDscp = 40 + IP_API_DSCP_EF IPDscp = 46 + IP_API_DSCP_CS6 IPDscp = 48 + IP_API_DSCP_CS7 IPDscp = 50 +) + +var IPDscp_name = map[uint8]string{ + 0: "IP_API_DSCP_CS0", + 8: "IP_API_DSCP_CS1", + 10: "IP_API_DSCP_AF11", + 12: "IP_API_DSCP_AF12", + 14: "IP_API_DSCP_AF13", + 16: "IP_API_DSCP_CS2", + 18: "IP_API_DSCP_AF21", + 20: "IP_API_DSCP_AF22", + 22: "IP_API_DSCP_AF23", + 24: "IP_API_DSCP_CS3", + 26: "IP_API_DSCP_AF31", + 28: "IP_API_DSCP_AF32", + 30: "IP_API_DSCP_AF33", + 32: "IP_API_DSCP_CS4", + 34: "IP_API_DSCP_AF41", + 36: "IP_API_DSCP_AF42", + 38: "IP_API_DSCP_AF43", + 40: "IP_API_DSCP_CS5", + 46: "IP_API_DSCP_EF", + 48: "IP_API_DSCP_CS6", + 50: "IP_API_DSCP_CS7", +} + +var IPDscp_value = map[string]uint8{ + "IP_API_DSCP_CS0": 0, + "IP_API_DSCP_CS1": 8, + "IP_API_DSCP_AF11": 10, + "IP_API_DSCP_AF12": 12, + "IP_API_DSCP_AF13": 14, + "IP_API_DSCP_CS2": 16, + "IP_API_DSCP_AF21": 18, + "IP_API_DSCP_AF22": 20, + "IP_API_DSCP_AF23": 22, + "IP_API_DSCP_CS3": 24, + "IP_API_DSCP_AF31": 26, + "IP_API_DSCP_AF32": 28, + "IP_API_DSCP_AF33": 30, + "IP_API_DSCP_CS4": 32, + "IP_API_DSCP_AF41": 34, + "IP_API_DSCP_AF42": 36, + "IP_API_DSCP_AF43": 38, + "IP_API_DSCP_CS5": 40, + "IP_API_DSCP_EF": 46, + "IP_API_DSCP_CS6": 48, + "IP_API_DSCP_CS7": 50, +} + +func (x IPDscp) String() string { + s, ok := IPDscp_name[uint8(x)] + if ok { + return s + } + return strconv.Itoa(int(x)) +} + +// IPEcn represents VPP binary API enum 'ip_ecn'. +type IPEcn uint8 + +const ( + IP_API_ECN_NONE IPEcn = 0 + IP_API_ECN_ECT0 IPEcn = 1 + IP_API_ECN_ECT1 IPEcn = 2 + IP_API_ECN_CE IPEcn = 3 +) + +var IPEcn_name = map[uint8]string{ + 0: "IP_API_ECN_NONE", + 1: "IP_API_ECN_ECT0", + 2: "IP_API_ECN_ECT1", + 3: "IP_API_ECN_CE", +} + +var IPEcn_value = map[string]uint8{ + "IP_API_ECN_NONE": 0, + "IP_API_ECN_ECT0": 1, + "IP_API_ECN_ECT1": 2, + "IP_API_ECN_CE": 3, +} + +func (x IPEcn) String() string { + s, ok := IPEcn_name[uint8(x)] + if ok { + return s + } + return strconv.Itoa(int(x)) +} + // IPProto represents VPP binary API enum 'ip_proto'. type IPProto uint32 const ( - IP_API_PROTO_TCP IPProto = 6 - IP_API_PROTO_UDP IPProto = 17 - IP_API_PROTO_EIGRP IPProto = 88 - IP_API_PROTO_OSPF IPProto = 89 + IP_API_PROTO_HOPOPT IPProto = 0 + IP_API_PROTO_ICMP IPProto = 1 + IP_API_PROTO_IGMP IPProto = 2 + IP_API_PROTO_TCP IPProto = 6 + IP_API_PROTO_UDP IPProto = 17 + IP_API_PROTO_GRE IPProto = 47 + IP_API_PROTO_AH IPProto = 50 + IP_API_PROTO_ESP IPProto = 51 + IP_API_PROTO_EIGRP IPProto = 88 + IP_API_PROTO_OSPF IPProto = 89 + IP_API_PROTO_SCTP IPProto = 132 + IP_API_PROTO_RESERVED IPProto = 255 ) var IPProto_name = map[uint32]string{ - 6: "IP_API_PROTO_TCP", - 17: "IP_API_PROTO_UDP", - 88: "IP_API_PROTO_EIGRP", - 89: "IP_API_PROTO_OSPF", + 0: "IP_API_PROTO_HOPOPT", + 1: "IP_API_PROTO_ICMP", + 2: "IP_API_PROTO_IGMP", + 6: "IP_API_PROTO_TCP", + 17: "IP_API_PROTO_UDP", + 47: "IP_API_PROTO_GRE", + 50: "IP_API_PROTO_AH", + 51: "IP_API_PROTO_ESP", + 88: "IP_API_PROTO_EIGRP", + 89: "IP_API_PROTO_OSPF", + 132: "IP_API_PROTO_SCTP", + 255: "IP_API_PROTO_RESERVED", } var IPProto_value = map[string]uint32{ - "IP_API_PROTO_TCP": 6, - "IP_API_PROTO_UDP": 17, - "IP_API_PROTO_EIGRP": 88, - "IP_API_PROTO_OSPF": 89, + "IP_API_PROTO_HOPOPT": 0, + "IP_API_PROTO_ICMP": 1, + "IP_API_PROTO_IGMP": 2, + "IP_API_PROTO_TCP": 6, + "IP_API_PROTO_UDP": 17, + "IP_API_PROTO_GRE": 47, + "IP_API_PROTO_AH": 50, + "IP_API_PROTO_ESP": 51, + "IP_API_PROTO_EIGRP": 88, + "IP_API_PROTO_OSPF": 89, + "IP_API_PROTO_SCTP": 132, + "IP_API_PROTO_RESERVED": 255, } func (x IPProto) String() string { diff --git a/plugins/vpp/binapi/vpp1908/punt/punt.ba.go b/plugins/vpp/binapi/vpp1908/punt/punt.ba.go index 335d504e37..9d5f58978c 100644 --- a/plugins/vpp/binapi/vpp1908/punt/punt.ba.go +++ b/plugins/vpp/binapi/vpp1908/punt/punt.ba.go @@ -5,7 +5,7 @@ Package punt is a generated VPP binary API for 'punt' module. It consists of: - 3 enums + 5 enums 2 aliases 10 types 2 unions @@ -29,7 +29,7 @@ const ( // APIVersion is the API version of this module. APIVersion = "2.1.0" // VersionCrc is the CRC of this module. - VersionCrc = 0xf01c2fb8 + VersionCrc = 0xd6aa99ad ) // AddressFamily represents VPP binary API enum 'address_family'. @@ -58,28 +58,167 @@ func (x AddressFamily) String() string { return strconv.Itoa(int(x)) } +// IPDscp represents VPP binary API enum 'ip_dscp'. +type IPDscp uint8 + +const ( + IP_API_DSCP_CS0 IPDscp = 0 + IP_API_DSCP_CS1 IPDscp = 8 + IP_API_DSCP_AF11 IPDscp = 10 + IP_API_DSCP_AF12 IPDscp = 12 + IP_API_DSCP_AF13 IPDscp = 14 + IP_API_DSCP_CS2 IPDscp = 16 + IP_API_DSCP_AF21 IPDscp = 18 + IP_API_DSCP_AF22 IPDscp = 20 + IP_API_DSCP_AF23 IPDscp = 22 + IP_API_DSCP_CS3 IPDscp = 24 + IP_API_DSCP_AF31 IPDscp = 26 + IP_API_DSCP_AF32 IPDscp = 28 + IP_API_DSCP_AF33 IPDscp = 30 + IP_API_DSCP_CS4 IPDscp = 32 + IP_API_DSCP_AF41 IPDscp = 34 + IP_API_DSCP_AF42 IPDscp = 36 + IP_API_DSCP_AF43 IPDscp = 38 + IP_API_DSCP_CS5 IPDscp = 40 + IP_API_DSCP_EF IPDscp = 46 + IP_API_DSCP_CS6 IPDscp = 48 + IP_API_DSCP_CS7 IPDscp = 50 +) + +var IPDscp_name = map[uint8]string{ + 0: "IP_API_DSCP_CS0", + 8: "IP_API_DSCP_CS1", + 10: "IP_API_DSCP_AF11", + 12: "IP_API_DSCP_AF12", + 14: "IP_API_DSCP_AF13", + 16: "IP_API_DSCP_CS2", + 18: "IP_API_DSCP_AF21", + 20: "IP_API_DSCP_AF22", + 22: "IP_API_DSCP_AF23", + 24: "IP_API_DSCP_CS3", + 26: "IP_API_DSCP_AF31", + 28: "IP_API_DSCP_AF32", + 30: "IP_API_DSCP_AF33", + 32: "IP_API_DSCP_CS4", + 34: "IP_API_DSCP_AF41", + 36: "IP_API_DSCP_AF42", + 38: "IP_API_DSCP_AF43", + 40: "IP_API_DSCP_CS5", + 46: "IP_API_DSCP_EF", + 48: "IP_API_DSCP_CS6", + 50: "IP_API_DSCP_CS7", +} + +var IPDscp_value = map[string]uint8{ + "IP_API_DSCP_CS0": 0, + "IP_API_DSCP_CS1": 8, + "IP_API_DSCP_AF11": 10, + "IP_API_DSCP_AF12": 12, + "IP_API_DSCP_AF13": 14, + "IP_API_DSCP_CS2": 16, + "IP_API_DSCP_AF21": 18, + "IP_API_DSCP_AF22": 20, + "IP_API_DSCP_AF23": 22, + "IP_API_DSCP_CS3": 24, + "IP_API_DSCP_AF31": 26, + "IP_API_DSCP_AF32": 28, + "IP_API_DSCP_AF33": 30, + "IP_API_DSCP_CS4": 32, + "IP_API_DSCP_AF41": 34, + "IP_API_DSCP_AF42": 36, + "IP_API_DSCP_AF43": 38, + "IP_API_DSCP_CS5": 40, + "IP_API_DSCP_EF": 46, + "IP_API_DSCP_CS6": 48, + "IP_API_DSCP_CS7": 50, +} + +func (x IPDscp) String() string { + s, ok := IPDscp_name[uint8(x)] + if ok { + return s + } + return strconv.Itoa(int(x)) +} + +// IPEcn represents VPP binary API enum 'ip_ecn'. +type IPEcn uint8 + +const ( + IP_API_ECN_NONE IPEcn = 0 + IP_API_ECN_ECT0 IPEcn = 1 + IP_API_ECN_ECT1 IPEcn = 2 + IP_API_ECN_CE IPEcn = 3 +) + +var IPEcn_name = map[uint8]string{ + 0: "IP_API_ECN_NONE", + 1: "IP_API_ECN_ECT0", + 2: "IP_API_ECN_ECT1", + 3: "IP_API_ECN_CE", +} + +var IPEcn_value = map[string]uint8{ + "IP_API_ECN_NONE": 0, + "IP_API_ECN_ECT0": 1, + "IP_API_ECN_ECT1": 2, + "IP_API_ECN_CE": 3, +} + +func (x IPEcn) String() string { + s, ok := IPEcn_name[uint8(x)] + if ok { + return s + } + return strconv.Itoa(int(x)) +} + // IPProto represents VPP binary API enum 'ip_proto'. type IPProto uint32 const ( - IP_API_PROTO_TCP IPProto = 6 - IP_API_PROTO_UDP IPProto = 17 - IP_API_PROTO_EIGRP IPProto = 88 - IP_API_PROTO_OSPF IPProto = 89 + IP_API_PROTO_HOPOPT IPProto = 0 + IP_API_PROTO_ICMP IPProto = 1 + IP_API_PROTO_IGMP IPProto = 2 + IP_API_PROTO_TCP IPProto = 6 + IP_API_PROTO_UDP IPProto = 17 + IP_API_PROTO_GRE IPProto = 47 + IP_API_PROTO_AH IPProto = 50 + IP_API_PROTO_ESP IPProto = 51 + IP_API_PROTO_EIGRP IPProto = 88 + IP_API_PROTO_OSPF IPProto = 89 + IP_API_PROTO_SCTP IPProto = 132 + IP_API_PROTO_RESERVED IPProto = 255 ) var IPProto_name = map[uint32]string{ - 6: "IP_API_PROTO_TCP", - 17: "IP_API_PROTO_UDP", - 88: "IP_API_PROTO_EIGRP", - 89: "IP_API_PROTO_OSPF", + 0: "IP_API_PROTO_HOPOPT", + 1: "IP_API_PROTO_ICMP", + 2: "IP_API_PROTO_IGMP", + 6: "IP_API_PROTO_TCP", + 17: "IP_API_PROTO_UDP", + 47: "IP_API_PROTO_GRE", + 50: "IP_API_PROTO_AH", + 51: "IP_API_PROTO_ESP", + 88: "IP_API_PROTO_EIGRP", + 89: "IP_API_PROTO_OSPF", + 132: "IP_API_PROTO_SCTP", + 255: "IP_API_PROTO_RESERVED", } var IPProto_value = map[string]uint32{ - "IP_API_PROTO_TCP": 6, - "IP_API_PROTO_UDP": 17, - "IP_API_PROTO_EIGRP": 88, - "IP_API_PROTO_OSPF": 89, + "IP_API_PROTO_HOPOPT": 0, + "IP_API_PROTO_ICMP": 1, + "IP_API_PROTO_IGMP": 2, + "IP_API_PROTO_TCP": 6, + "IP_API_PROTO_UDP": 17, + "IP_API_PROTO_GRE": 47, + "IP_API_PROTO_AH": 50, + "IP_API_PROTO_ESP": 51, + "IP_API_PROTO_EIGRP": 88, + "IP_API_PROTO_OSPF": 89, + "IP_API_PROTO_SCTP": 132, + "IP_API_PROTO_RESERVED": 255, } func (x IPProto) String() string { @@ -347,13 +486,15 @@ func (*PuntReasonDetails) GetMessageType() api.MessageType { } // PuntReasonDump represents VPP binary API message 'punt_reason_dump'. -type PuntReasonDump struct{} +type PuntReasonDump struct { + Reason PuntReason +} func (*PuntReasonDump) GetMessageName() string { return "punt_reason_dump" } func (*PuntReasonDump) GetCrcString() string { - return "51077d14" + return "bf8f10da" } func (*PuntReasonDump) GetMessageType() api.MessageType { return api.RequestMessage diff --git a/plugins/vpp/binapi/vpp1908/vpe/vpe.ba.go b/plugins/vpp/binapi/vpp1908/vpe/vpe.ba.go index e3f937673d..e25b73caaf 100644 --- a/plugins/vpp/binapi/vpp1908/vpe/vpe.ba.go +++ b/plugins/vpp/binapi/vpp1908/vpe/vpe.ba.go @@ -5,9 +5,10 @@ Package vpe is a generated VPP binary API for 'vpe' module. It consists of: + 1 enum 1 type - 18 messages - 9 services + 26 messages + 13 services */ package vpe @@ -24,11 +25,58 @@ const ( // ModuleName is the name of this module. ModuleName = "vpe" // APIVersion is the API version of this module. - APIVersion = "1.1.0" + APIVersion = "1.4.0" // VersionCrc is the CRC of this module. - VersionCrc = 0x2cc8d629 + VersionCrc = 0xf4bcb773 ) +// LogLevel represents VPP binary API enum 'log_level'. +type LogLevel uint32 + +const ( + VPE_API_LOG_LEVEL_EMERG LogLevel = 0 + VPE_API_LOG_LEVEL_ALERT LogLevel = 1 + VPE_API_LOG_LEVEL_CRIT LogLevel = 2 + VPE_API_LOG_LEVEL_ERR LogLevel = 3 + VPE_API_LOG_LEVEL_WARNING LogLevel = 4 + VPE_API_LOG_LEVEL_NOTICE LogLevel = 5 + VPE_API_LOG_LEVEL_INFO LogLevel = 6 + VPE_API_LOG_LEVEL_DEBUG LogLevel = 7 + VPE_API_LOG_LEVEL_DISABLED LogLevel = 8 +) + +var LogLevel_name = map[uint32]string{ + 0: "VPE_API_LOG_LEVEL_EMERG", + 1: "VPE_API_LOG_LEVEL_ALERT", + 2: "VPE_API_LOG_LEVEL_CRIT", + 3: "VPE_API_LOG_LEVEL_ERR", + 4: "VPE_API_LOG_LEVEL_WARNING", + 5: "VPE_API_LOG_LEVEL_NOTICE", + 6: "VPE_API_LOG_LEVEL_INFO", + 7: "VPE_API_LOG_LEVEL_DEBUG", + 8: "VPE_API_LOG_LEVEL_DISABLED", +} + +var LogLevel_value = map[string]uint32{ + "VPE_API_LOG_LEVEL_EMERG": 0, + "VPE_API_LOG_LEVEL_ALERT": 1, + "VPE_API_LOG_LEVEL_CRIT": 2, + "VPE_API_LOG_LEVEL_ERR": 3, + "VPE_API_LOG_LEVEL_WARNING": 4, + "VPE_API_LOG_LEVEL_NOTICE": 5, + "VPE_API_LOG_LEVEL_INFO": 6, + "VPE_API_LOG_LEVEL_DEBUG": 7, + "VPE_API_LOG_LEVEL_DISABLED": 8, +} + +func (x LogLevel) String() string { + s, ok := LogLevel_name[uint32(x)] + if ok { + return s + } + return strconv.Itoa(int(x)) +} + // ThreadData represents VPP binary API type 'thread_data'. type ThreadData struct { ID uint32 @@ -170,6 +218,68 @@ func (*ControlPingReply) GetMessageType() api.MessageType { return api.ReplyMessage } +// GetF64EndianValue represents VPP binary API message 'get_f64_endian_value'. +type GetF64EndianValue struct { + F64One float64 +} + +func (*GetF64EndianValue) GetMessageName() string { + return "get_f64_endian_value" +} +func (*GetF64EndianValue) GetCrcString() string { + return "809fcd44" +} +func (*GetF64EndianValue) GetMessageType() api.MessageType { + return api.RequestMessage +} + +// GetF64EndianValueReply represents VPP binary API message 'get_f64_endian_value_reply'. +type GetF64EndianValueReply struct { + Retval uint32 + F64OneResult float64 +} + +func (*GetF64EndianValueReply) GetMessageName() string { + return "get_f64_endian_value_reply" +} +func (*GetF64EndianValueReply) GetCrcString() string { + return "7e02e404" +} +func (*GetF64EndianValueReply) GetMessageType() api.MessageType { + return api.ReplyMessage +} + +// GetF64IncrementByOne represents VPP binary API message 'get_f64_increment_by_one'. +type GetF64IncrementByOne struct { + F64Value float64 +} + +func (*GetF64IncrementByOne) GetMessageName() string { + return "get_f64_increment_by_one" +} +func (*GetF64IncrementByOne) GetCrcString() string { + return "b64f027e" +} +func (*GetF64IncrementByOne) GetMessageType() api.MessageType { + return api.RequestMessage +} + +// GetF64IncrementByOneReply represents VPP binary API message 'get_f64_increment_by_one_reply'. +type GetF64IncrementByOneReply struct { + Retval uint32 + F64Value float64 +} + +func (*GetF64IncrementByOneReply) GetMessageName() string { + return "get_f64_increment_by_one_reply" +} +func (*GetF64IncrementByOneReply) GetCrcString() string { + return "d25dbaa3" +} +func (*GetF64IncrementByOneReply) GetMessageType() api.MessageType { + return api.ReplyMessage +} + // GetNextIndex represents VPP binary API message 'get_next_index'. type GetNextIndex struct { NodeName []byte `struc:"[64]byte"` @@ -262,6 +372,43 @@ func (*GetNodeIndexReply) GetMessageType() api.MessageType { return api.ReplyMessage } +// LogDetails represents VPP binary API message 'log_details'. +type LogDetails struct { + TimestampTicks float64 + Level LogLevel + XXX_TimestampLen uint32 `struc:"sizeof=Timestamp"` + Timestamp string `binapi:",limit=24"` + XXX_MsgClassLen uint32 `struc:"sizeof=MsgClass"` + MsgClass string `binapi:",limit=32"` + XXX_MessageLen uint32 `struc:"sizeof=Message"` + Message string `binapi:",limit=256"` +} + +func (*LogDetails) GetMessageName() string { + return "log_details" +} +func (*LogDetails) GetCrcString() string { + return "91976545" +} +func (*LogDetails) GetMessageType() api.MessageType { + return api.ReplyMessage +} + +// LogDump represents VPP binary API message 'log_dump'. +type LogDump struct { + StartTimestamp float64 +} + +func (*LogDump) GetMessageName() string { + return "log_dump" +} +func (*LogDump) GetCrcString() string { + return "74fddb5f" +} +func (*LogDump) GetMessageType() api.MessageType { + return api.RequestMessage +} + // ShowThreads represents VPP binary API message 'show_threads'. type ShowThreads struct{} @@ -328,6 +475,35 @@ func (*ShowVersionReply) GetMessageType() api.MessageType { return api.ReplyMessage } +// ShowVpeSystemTimeTicks represents VPP binary API message 'show_vpe_system_time_ticks'. +type ShowVpeSystemTimeTicks struct{} + +func (*ShowVpeSystemTimeTicks) GetMessageName() string { + return "show_vpe_system_time_ticks" +} +func (*ShowVpeSystemTimeTicks) GetCrcString() string { + return "51077d14" +} +func (*ShowVpeSystemTimeTicks) GetMessageType() api.MessageType { + return api.RequestMessage +} + +// ShowVpeSystemTimeTicksReply represents VPP binary API message 'show_vpe_system_time_ticks_reply'. +type ShowVpeSystemTimeTicksReply struct { + Retval int32 + VpeSystemTimeTicks float64 +} + +func (*ShowVpeSystemTimeTicksReply) GetMessageName() string { + return "show_vpe_system_time_ticks_reply" +} +func (*ShowVpeSystemTimeTicksReply) GetCrcString() string { + return "5fa0885c" +} +func (*ShowVpeSystemTimeTicksReply) GetMessageType() api.MessageType { + return api.ReplyMessage +} + func init() { api.RegisterMessage((*AddNodeNext)(nil), "vpe.AddNodeNext") api.RegisterMessage((*AddNodeNextReply)(nil), "vpe.AddNodeNextReply") @@ -337,16 +513,24 @@ func init() { api.RegisterMessage((*CliReply)(nil), "vpe.CliReply") api.RegisterMessage((*ControlPing)(nil), "vpe.ControlPing") api.RegisterMessage((*ControlPingReply)(nil), "vpe.ControlPingReply") + api.RegisterMessage((*GetF64EndianValue)(nil), "vpe.GetF64EndianValue") + api.RegisterMessage((*GetF64EndianValueReply)(nil), "vpe.GetF64EndianValueReply") + api.RegisterMessage((*GetF64IncrementByOne)(nil), "vpe.GetF64IncrementByOne") + api.RegisterMessage((*GetF64IncrementByOneReply)(nil), "vpe.GetF64IncrementByOneReply") api.RegisterMessage((*GetNextIndex)(nil), "vpe.GetNextIndex") api.RegisterMessage((*GetNextIndexReply)(nil), "vpe.GetNextIndexReply") api.RegisterMessage((*GetNodeGraph)(nil), "vpe.GetNodeGraph") api.RegisterMessage((*GetNodeGraphReply)(nil), "vpe.GetNodeGraphReply") api.RegisterMessage((*GetNodeIndex)(nil), "vpe.GetNodeIndex") api.RegisterMessage((*GetNodeIndexReply)(nil), "vpe.GetNodeIndexReply") + api.RegisterMessage((*LogDetails)(nil), "vpe.LogDetails") + api.RegisterMessage((*LogDump)(nil), "vpe.LogDump") api.RegisterMessage((*ShowThreads)(nil), "vpe.ShowThreads") api.RegisterMessage((*ShowThreadsReply)(nil), "vpe.ShowThreadsReply") api.RegisterMessage((*ShowVersion)(nil), "vpe.ShowVersion") api.RegisterMessage((*ShowVersionReply)(nil), "vpe.ShowVersionReply") + api.RegisterMessage((*ShowVpeSystemTimeTicks)(nil), "vpe.ShowVpeSystemTimeTicks") + api.RegisterMessage((*ShowVpeSystemTimeTicksReply)(nil), "vpe.ShowVpeSystemTimeTicksReply") } // Messages returns list of all messages in this module. @@ -360,30 +544,42 @@ func AllMessages() []api.Message { (*CliReply)(nil), (*ControlPing)(nil), (*ControlPingReply)(nil), + (*GetF64EndianValue)(nil), + (*GetF64EndianValueReply)(nil), + (*GetF64IncrementByOne)(nil), + (*GetF64IncrementByOneReply)(nil), (*GetNextIndex)(nil), (*GetNextIndexReply)(nil), (*GetNodeGraph)(nil), (*GetNodeGraphReply)(nil), (*GetNodeIndex)(nil), (*GetNodeIndexReply)(nil), + (*LogDetails)(nil), + (*LogDump)(nil), (*ShowThreads)(nil), (*ShowThreadsReply)(nil), (*ShowVersion)(nil), (*ShowVersionReply)(nil), + (*ShowVpeSystemTimeTicks)(nil), + (*ShowVpeSystemTimeTicksReply)(nil), } } // RPCService represents RPC service API for vpe module. type RPCService interface { + DumpLog(ctx context.Context, in *LogDump) (RPCService_DumpLogClient, error) AddNodeNext(ctx context.Context, in *AddNodeNext) (*AddNodeNextReply, error) Cli(ctx context.Context, in *Cli) (*CliReply, error) CliInband(ctx context.Context, in *CliInband) (*CliInbandReply, error) ControlPing(ctx context.Context, in *ControlPing) (*ControlPingReply, error) + GetF64EndianValue(ctx context.Context, in *GetF64EndianValue) (*GetF64EndianValueReply, error) + GetF64IncrementByOne(ctx context.Context, in *GetF64IncrementByOne) (*GetF64IncrementByOneReply, error) GetNextIndex(ctx context.Context, in *GetNextIndex) (*GetNextIndexReply, error) GetNodeGraph(ctx context.Context, in *GetNodeGraph) (*GetNodeGraphReply, error) GetNodeIndex(ctx context.Context, in *GetNodeIndex) (*GetNodeIndexReply, error) ShowThreads(ctx context.Context, in *ShowThreads) (*ShowThreadsReply, error) ShowVersion(ctx context.Context, in *ShowVersion) (*ShowVersionReply, error) + ShowVpeSystemTimeTicks(ctx context.Context, in *ShowVpeSystemTimeTicks) (*ShowVpeSystemTimeTicksReply, error) } type serviceClient struct { @@ -394,6 +590,32 @@ func NewServiceClient(ch api.Channel) RPCService { return &serviceClient{ch} } +func (c *serviceClient) DumpLog(ctx context.Context, in *LogDump) (RPCService_DumpLogClient, error) { + stream := c.ch.SendMultiRequest(in) + x := &serviceClient_DumpLogClient{stream} + return x, nil +} + +type RPCService_DumpLogClient interface { + Recv() (*LogDetails, error) +} + +type serviceClient_DumpLogClient struct { + api.MultiRequestCtx +} + +func (c *serviceClient_DumpLogClient) Recv() (*LogDetails, error) { + m := new(LogDetails) + stop, err := c.MultiRequestCtx.ReceiveReply(m) + if err != nil { + return nil, err + } + if stop { + return nil, io.EOF + } + return m, nil +} + func (c *serviceClient) AddNodeNext(ctx context.Context, in *AddNodeNext) (*AddNodeNextReply, error) { out := new(AddNodeNextReply) err := c.ch.SendRequest(in).ReceiveReply(out) @@ -430,6 +652,24 @@ func (c *serviceClient) ControlPing(ctx context.Context, in *ControlPing) (*Cont return out, nil } +func (c *serviceClient) GetF64EndianValue(ctx context.Context, in *GetF64EndianValue) (*GetF64EndianValueReply, error) { + out := new(GetF64EndianValueReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serviceClient) GetF64IncrementByOne(ctx context.Context, in *GetF64IncrementByOne) (*GetF64IncrementByOneReply, error) { + out := new(GetF64IncrementByOneReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + func (c *serviceClient) GetNextIndex(ctx context.Context, in *GetNextIndex) (*GetNextIndexReply, error) { out := new(GetNextIndexReply) err := c.ch.SendRequest(in).ReceiveReply(out) @@ -475,6 +715,15 @@ func (c *serviceClient) ShowVersion(ctx context.Context, in *ShowVersion) (*Show return out, nil } +func (c *serviceClient) ShowVpeSystemTimeTicks(ctx context.Context, in *ShowVpeSystemTimeTicks) (*ShowVpeSystemTimeTicksReply, error) { + out := new(ShowVpeSystemTimeTicksReply) + err := c.ch.SendRequest(in).ReceiveReply(out) + if err != nil { + return nil, err + } + return out, nil +} + // This is a compile-time assertion to ensure that this generated file // is compatible with the GoVPP api package it is being compiled against. // A compilation error at this line likely means your copy of the diff --git a/scripts/genbinapi.sh b/scripts/genbinapi.sh index 6314f60292..1e8943935f 100755 --- a/scripts/genbinapi.sh +++ b/scripts/genbinapi.sh @@ -5,4 +5,4 @@ set -euo pipefail go generate -x ./${VPP_BINAPI} find ${VPP_BINAPI} -maxdepth 2 -type f -name '*.patch' -exec \ - patch --verbose --no-backup-if-mismatch -p1 -i {} \; + patch --no-backup-if-mismatch -p1 -i {} \; diff --git a/scripts/install_protobuf.sh b/scripts/install_protobuf.sh old mode 100644 new mode 100755 diff --git a/vpp.env b/vpp.env index ec62eba68a..a104c32177 100644 --- a/vpp.env +++ b/vpp.env @@ -9,7 +9,7 @@ VPP_BINAPI_1901=plugins/vpp/binapi/vpp1901 VPP_IMG_1904=ligato/vpp-base:19.04 VPP_BINAPI_1904=plugins/vpp/binapi/vpp1904 # VPP 19.08-rc0 -VPP_IMG_1908=ligato/vpp-base:19.08-rc0.581-g3eea9de89 +VPP_IMG_1908=ligato/vpp-base:19.08-rc0.673-ga2e4451db VPP_BINAPI_1908=plugins/vpp/binapi/vpp1908 # default VPP VPP_DEFAULT=1904 \ No newline at end of file From ed775d686f39a825118e89732552fc00a47d4d09 Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Fri, 19 Jul 2019 13:34:49 +0200 Subject: [PATCH 03/10] Fix in Telemetry plugin and improvements for integration tests (#1414) * Add DumpInterface to vppcalls in ifplugin Signed-off-by: Ondrej Fabry * Cleanup vpp integration tests Signed-off-by: Ondrej Fabry * Fix file name Signed-off-by: Ondrej Fabry * Hide iptables warning when no config found Signed-off-by: Ondrej Fabry * Print shm warning directly into stderr Signed-off-by: Ondrej Fabry * Fix single interface dump for older VPP Signed-off-by: Ondrej Fabry * Fix retrieving memory stats in telemetry for VPP 19.08 Signed-off-by: Ondrej Fabry * Add tests for telemetry to VPP integration tests Signed-off-by: Ondrej Fabry * Fix integration tests - Skip some telemetry integration tests for VPP<=19.04 - Fix GetMemory in telemetry for VPP<=19.04 - Use hard-coded config for VPP - Use DOCKER_ARGS for custom arguments for docker Signed-off-by: Ondrej Fabry * Update GoVPP Signed-off-by: Ondrej Fabry --- Gopkg.lock | 4 +- plugins/govppmux/adapter_puregoclient.go | 26 +-- .../govppmux/vppcalls/vpp1901/vpe_vppcalls.go | 2 +- .../govppmux/vppcalls/vpp1904/vpe_vppcalls.go | 2 +- .../govppmux/vppcalls/vpp1908/vpe_vppcalls.go | 2 +- plugins/govppmux/vppcalls/vppcalls_api.go | 8 + .../linux/iptablesplugin/iptablesplugin.go | 6 +- .../vppcalls/vpp1901/telemetry_vppcalls.go | 5 +- .../vppcalls/vpp1904/telemetry_vppcalls.go | 7 +- .../vppcalls/vpp1908/telemetry_vppcalls.go | 7 +- .../vpp1908/telemetry_vppcalls_test.go | 26 ++- plugins/telemetry/vppcalls/vppcalls_api.go | 18 +- plugins/vpp/ifplugin/vppcalls/if_vppcalls.go | 4 +- .../vpp1901/dump_interface_vppcalls.go | 15 ++ .../vpp1904/dump_interface_vppcalls.go | 15 ++ .../vpp1908/dump_interface_vppcalls.go | 29 +++- ...vppcals_test.go => subif_vppcalls_test.go} | 0 tests/integration/vpp/000_initial_test.go | 18 +- tests/integration/vpp/001_telemetry_test.go | 68 ++++++++ ...1_basic_test.go => 010_interfaces_test.go} | 112 ++++++------ tests/integration/vpp/020_routes_test.go | 65 +++++++ tests/integration/vpp/integration_test.go | 160 +++++++++++++----- tests/integration/vpp_integration.sh | 48 ++++-- .../adapter/socketclient/socketclient.go | 26 ++- .../adapter/statsclient/stat_segment.go | 4 +- .../adapter/statsclient/statsclient.go | 35 ++-- vendor/git.fd.io/govpp.git/api/stats.go | 14 ++ 27 files changed, 538 insertions(+), 188 deletions(-) rename plugins/vpp/ifplugin/vppcalls/vpp1908/{subif_vppcals_test.go => subif_vppcalls_test.go} (100%) create mode 100644 tests/integration/vpp/001_telemetry_test.go rename tests/integration/vpp/{001_basic_test.go => 010_interfaces_test.go} (51%) create mode 100644 tests/integration/vpp/020_routes_test.go diff --git a/Gopkg.lock b/Gopkg.lock index 8915f59584..1989161da5 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -3,7 +3,7 @@ [[projects]] branch = "master" - digest = "1:2f8279ed810b92fb539860ddc3d0ddf120af9deb7ab91516472ac0b88b112165" + digest = "1:576638fbd32f0237520d280e7df80092293efd6780f639546bb258768f150c83" name = "git.fd.io/govpp.git" packages = [ "adapter", @@ -19,7 +19,7 @@ "examples/binapi/memclnt", ] pruneopts = "UT" - revision = "4dca07c803308611275f78b490ac0352c1052fe2" + revision = "bde85d422c7949ec32fb067e9c36320ccc47fb9e" [[projects]] branch = "master" diff --git a/plugins/govppmux/adapter_puregoclient.go b/plugins/govppmux/adapter_puregoclient.go index 4e8e6c9357..0f542641f8 100644 --- a/plugins/govppmux/adapter_puregoclient.go +++ b/plugins/govppmux/adapter_puregoclient.go @@ -17,29 +17,33 @@ package govppmux import ( + "fmt" + "os" + "git.fd.io/govpp.git/adapter" "git.fd.io/govpp.git/adapter/socketclient" "git.fd.io/govpp.git/adapter/statsclient" - "github.com/ligato/cn-infra/logging" ) +const noShmWarning = `Using shared memory for VPP binary API is not currently supported in pure Go client! + + To use socket client for VPP binary API (recommended): + - unset GOVPPMUX_NOSOCK environment variable + - remove these settings from govpp.conf config: shm-prefix, connect-via-shm + + If you still want to use shared memory for VPP binary API: + - compile your agent with this build tag: vppapiclient + - vppapiclient requires CGo and needs VPP to be installed +` + // NewVppAdapter returns VPP binary API adapter, implemented as pure Go client. func NewVppAdapter(addr string, useShm bool) adapter.VppAPI { if useShm { - logging.Warnf(`Using shared memory for VPP binary API is not currently supported in pure Go client! - - To use socket client for VPP binary API: - - unset GOVPPMUX_NOSOCK environment variable - - remove these settings from govpp.conf config: shm-prefix, connect-via-shm - - If you still want to use shared memory for VPP binary API (not recommended): - - compile your agent with this build tag: vppapiclient -`) + fmt.Fprintf(os.Stderr, noShmWarning) panic("No implementation for shared memory in pure Go client!") } // addr is used as socket path return socketclient.NewVppClient(addr) - } // NewStatsAdapter returns VPP stats API adapter, implemented as pure Go client. diff --git a/plugins/govppmux/vppcalls/vpp1901/vpe_vppcalls.go b/plugins/govppmux/vppcalls/vpp1901/vpe_vppcalls.go index 5c41fe464b..f217d22883 100644 --- a/plugins/govppmux/vppcalls/vpp1901/vpe_vppcalls.go +++ b/plugins/govppmux/vppcalls/vpp1901/vpe_vppcalls.go @@ -31,7 +31,7 @@ func init() { msgs = append(msgs, vpe.AllMessages()...) msgs = append(msgs, memclnt.AllMessages()...) - vppcalls.Versions["vpp1901"] = vppcalls.HandlerVersion{ + vppcalls.Versions["19.01"] = vppcalls.HandlerVersion{ Msgs: msgs, New: func(ch govppapi.Channel) vppcalls.VpeVppAPI { return NewVpeHandler(ch) diff --git a/plugins/govppmux/vppcalls/vpp1904/vpe_vppcalls.go b/plugins/govppmux/vppcalls/vpp1904/vpe_vppcalls.go index 745e7bfca6..f5950165c6 100644 --- a/plugins/govppmux/vppcalls/vpp1904/vpe_vppcalls.go +++ b/plugins/govppmux/vppcalls/vpp1904/vpe_vppcalls.go @@ -31,7 +31,7 @@ func init() { msgs = append(msgs, vpe.AllMessages()...) msgs = append(msgs, memclnt.AllMessages()...) - vppcalls.Versions["vpp1904"] = vppcalls.HandlerVersion{ + vppcalls.Versions["19.04"] = vppcalls.HandlerVersion{ Msgs: msgs, New: func(ch govppapi.Channel) vppcalls.VpeVppAPI { return NewVpeHandler(ch) diff --git a/plugins/govppmux/vppcalls/vpp1908/vpe_vppcalls.go b/plugins/govppmux/vppcalls/vpp1908/vpe_vppcalls.go index d02b394662..6673d4a628 100644 --- a/plugins/govppmux/vppcalls/vpp1908/vpe_vppcalls.go +++ b/plugins/govppmux/vppcalls/vpp1908/vpe_vppcalls.go @@ -31,7 +31,7 @@ func init() { msgs = append(msgs, vpe.AllMessages()...) msgs = append(msgs, memclnt.AllMessages()...) - vppcalls.Versions["vpp1908"] = vppcalls.HandlerVersion{ + vppcalls.Versions["19.08"] = vppcalls.HandlerVersion{ Msgs: msgs, New: func(ch govppapi.Channel) vppcalls.VpeVppAPI { return NewVpeHandler(ch) diff --git a/plugins/govppmux/vppcalls/vppcalls_api.go b/plugins/govppmux/vppcalls/vppcalls_api.go index 4bf8b6de89..7c17c4b033 100644 --- a/plugins/govppmux/vppcalls/vppcalls_api.go +++ b/plugins/govppmux/vppcalls/vppcalls_api.go @@ -15,6 +15,14 @@ type VersionInfo struct { BuildDirectory string } +// Release returns version in shortened format YY.MM that describes release. +func (v VersionInfo) Release() string { + if len(v.Version) < 5 { + return "" + } + return v.Version[:5] +} + // VpeInfo contains information about VPP connection and process. type VpeInfo struct { PID uint32 diff --git a/plugins/linux/iptablesplugin/iptablesplugin.go b/plugins/linux/iptablesplugin/iptablesplugin.go index ff5fd7ab52..4c3e1c21cd 100644 --- a/plugins/linux/iptablesplugin/iptablesplugin.go +++ b/plugins/linux/iptablesplugin/iptablesplugin.go @@ -36,7 +36,8 @@ type IPTablesPlugin struct { Deps // From configuration file - disabled bool + disabled bool + configFound bool // system handlers iptHandler linuxcalls.IPTablesAPI @@ -75,7 +76,7 @@ func (p *IPTablesPlugin) Init() error { // init iptables handler p.iptHandler = linuxcalls.NewIPTablesHandler() err = p.iptHandler.Init() - if err != nil { + if err != nil && p.configFound { // just warn here, iptables / ip6tables just may not be installed - will return // an error by attempt to configure it p.Log.Warnf("Error by initializing iptables handler: %v", err) @@ -112,5 +113,6 @@ func (p *IPTablesPlugin) retrieveConfig() (*Config, error) { if err != nil { return nil, err } + p.configFound = true return config, err } diff --git a/plugins/telemetry/vppcalls/vpp1901/telemetry_vppcalls.go b/plugins/telemetry/vppcalls/vpp1901/telemetry_vppcalls.go index 67b6583874..84a522a633 100644 --- a/plugins/telemetry/vppcalls/vpp1901/telemetry_vppcalls.go +++ b/plugins/telemetry/vppcalls/vpp1901/telemetry_vppcalls.go @@ -63,14 +63,15 @@ var ( memoryRe = regexp.MustCompile( `Thread\s+(\d+)\s+(\w+).?\s+` + `virtual memory start 0x[0-9abcdef]+, size ([\dkmg\.]+), ([\dkmg\.]+) pages, page size ([\dkmg\.]+)\s+` + - `(?:\s+(?:numa [\d]+|not mapped|unknown): [\dkmg\.]+ pages, [\dkmg\.]+\s+)+\s+` + + `(?:page information not available.*\s+)*` + + `(?:(?:\s+(?:numa [\d]+|not mapped|unknown): [\dkmg\.]+ pages, [\dkmg\.]+\s+)+\s+)*` + `\s+total: ([\dkmgKMG\.]+), used: ([\dkmgKMG\.]+), free: ([\dkmgKMG\.]+), trimmable: ([\dkmgKMG\.]+)`, ) ) // GetMemory retrieves `show memory` info. func (h *TelemetryHandler) GetMemory(ctx context.Context) (*vppcalls.MemoryInfo, error) { - data, err := h.RunCli("show memory") + data, err := h.RunCli("show memory main-heap") if err != nil { return nil, err } diff --git a/plugins/telemetry/vppcalls/vpp1904/telemetry_vppcalls.go b/plugins/telemetry/vppcalls/vpp1904/telemetry_vppcalls.go index 5a86ae358b..a8ee54bd03 100644 --- a/plugins/telemetry/vppcalls/vpp1904/telemetry_vppcalls.go +++ b/plugins/telemetry/vppcalls/vpp1904/telemetry_vppcalls.go @@ -57,8 +57,9 @@ var ( // Regular expression to parse output from `show memory` memoryRe = regexp.MustCompile( `Thread\s+(\d+)\s+(\w+).?\s+` + - `virtual memory start 0x[0-9abcdef]+, size ([\dkmg\.]+), ([\dkmg\.]+) pages, page size ([\dkmg\.]+)\s+` + - `(?:\s+(?:numa [\d]+|not mapped|unknown): [\dkmg\.]+ pages, [\dkmg\.]+\s+)+\s+` + + `virtual memory start 0x[0-9a-f]+, size ([\dkmg\.]+), ([\dkmg\.]+) pages, page size ([\dkmg\.]+)\s+` + + `(?:page information not available.*\s+)*` + + `(?:(?:\s+(?:numa [\d]+|not mapped|unknown): [\dkmg\.]+ pages, [\dkmg\.]+\s+)+\s+)*` + `\s+total: ([\dkmgKMG\.]+), used: ([\dkmgKMG\.]+), free: ([\dkmgKMG\.]+), trimmable: ([\dkmgKMG\.]+)`, ) ) @@ -69,7 +70,7 @@ func (h *TelemetryHandler) GetMemory(ctx context.Context) (*vppcalls.MemoryInfo, } func (h *TelemetryHandler) getMemoryCLI(ctx context.Context) (*vppcalls.MemoryInfo, error) { - data, err := h.vpe.RunCli("show memory") + data, err := h.vpe.RunCli("show memory main-heap") if err != nil { return nil, err } diff --git a/plugins/telemetry/vppcalls/vpp1908/telemetry_vppcalls.go b/plugins/telemetry/vppcalls/vpp1908/telemetry_vppcalls.go index 0a1e71a0d4..fb7f18c24c 100644 --- a/plugins/telemetry/vppcalls/vpp1908/telemetry_vppcalls.go +++ b/plugins/telemetry/vppcalls/vpp1908/telemetry_vppcalls.go @@ -57,8 +57,9 @@ var ( // Regular expression to parse output from `show memory` memoryRe = regexp.MustCompile( `Thread\s+(\d+)\s+(\w+).?\s+` + - `virtual memory start 0x[0-9abcdef]+, size ([\dkmg\.]+), ([\dkmg\.]+) pages, page size ([\dkmg\.]+)\s+` + - `(?:\s+(?:numa [\d]+|not mapped|unknown): [\dkmg\.]+ pages, [\dkmg\.]+\s+)+\s+` + + `virtual memory start 0x[0-9a-f]+, size ([\dkmg\.]+), ([\dkmg\.]+) pages, page size ([\dkmg\.]+)\s+` + + `(?:page information not available.*\s+)*` + + `(?:(?:\s+(?:numa [\d]+|not mapped|unknown): [\dkmg\.]+ pages, [\dkmg\.]+\s+)*\s+)*` + `\s+total: ([\dkmgKMG\.]+), used: ([\dkmgKMG\.]+), free: ([\dkmgKMG\.]+), trimmable: ([\dkmgKMG\.]+)`, ) ) @@ -69,7 +70,7 @@ func (h *TelemetryHandler) GetMemory(ctx context.Context) (*vppcalls.MemoryInfo, } func (h *TelemetryHandler) getMemoryCLI(ctx context.Context) (*vppcalls.MemoryInfo, error) { - data, err := h.vpe.RunCli("show memory") + data, err := h.vpe.RunCli("show memory main-heap") if err != nil { return nil, err } diff --git a/plugins/telemetry/vppcalls/vpp1908/telemetry_vppcalls_test.go b/plugins/telemetry/vppcalls/vpp1908/telemetry_vppcalls_test.go index 1ca9b4803e..dda265d1dc 100644 --- a/plugins/telemetry/vppcalls/vpp1908/telemetry_vppcalls_test.go +++ b/plugins/telemetry/vppcalls/vpp1908/telemetry_vppcalls_test.go @@ -16,13 +16,14 @@ package vpp1908_test import ( "context" - "github.com/ligato/vpp-agent/plugins/telemetry/vppcalls/vpp1908" "testing" + . "github.com/onsi/gomega" + "github.com/ligato/vpp-agent/plugins/telemetry/vppcalls" + "github.com/ligato/vpp-agent/plugins/telemetry/vppcalls/vpp1908" "github.com/ligato/vpp-agent/plugins/vpp/binapi/vpp1908/vpe" "github.com/ligato/vpp-agent/plugins/vpp/vppcallmock" - . "github.com/onsi/gomega" ) func TestGetBuffers(t *testing.T) { @@ -410,6 +411,27 @@ no traced allocations Reclaimed: 996.12e6, }, }, + { + name: "19.08 update", + reply: `Thread 0 vpp_main + virtual memory start 0x7ff41b3ca000, size 1048640k, 262160 pages, page size 4k + page information not available (errno 1) + total: 1.00G, used: 19.81M, free: 1004.25M, trimmable: 1004.24M +`, + threadCount: 1, + threadIdx: 0, + thread: vppcalls.MemoryThread{ + ID: 0, + Name: "vpp_main", + Size: 1048.64e6, + Pages: 262160, + PageSize: 4000, + Used: 19.81e6, + Total: 1e9, + Free: 1004.25e6, + Reclaimed: 1004.24e6, + }, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { diff --git a/plugins/telemetry/vppcalls/vppcalls_api.go b/plugins/telemetry/vppcalls/vppcalls_api.go index d77804167d..ead710f2e7 100644 --- a/plugins/telemetry/vppcalls/vppcalls_api.go +++ b/plugins/telemetry/vppcalls/vppcalls_api.go @@ -19,7 +19,8 @@ import ( govppapi "git.fd.io/govpp.git/api" log "github.com/ligato/cn-infra/logging" - "github.com/ligato/vpp-agent/plugins/govppmux" + + "github.com/ligato/vpp-agent/plugins/govppmux/vppcalls" ) var Versions = map[string]HandlerVersion{} @@ -152,19 +153,20 @@ type BuffersItem struct { NumFree uint64 `json:"num_free"` } -func CompatibleTelemetryHandler(ch govppapi.Channel, vpp govppmux.StatsAPI) TelemetryVppAPI { - status, err := vpp.VPPInfo() +func CompatibleTelemetryHandler(ch govppapi.Channel, vpp govppapi.StatsProvider) TelemetryVppAPI { + vpe := vppcalls.CompatibleVpeHandler(ch) + info, err := vpe.GetVersionInfo() if err != nil { - log.Warnf("retrieving VPP status failed: %v", err) + log.Warnf("retrieving VPP info failed: %v", err) return nil } - if status.Connected { - ver := status.GetReleaseVersion() + if ver := info.Release(); ver != "" { + log.Debug("telemetry checking release: ", ver) if h, ok := Versions[ver]; ok { if err := ch.CheckCompatiblity(h.Msgs...); err != nil { - log.Debugf("version %s not compatible", ver) + log.Debugf("telemetry version %s not compatible: %v", ver, err) } - log.Debug("found compatible version: ", ver) + log.Debug("telemetry found compatible release: ", ver) return h.New(ch, vpp) } } diff --git a/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go index 04d84dd4e2..9acdd70185 100644 --- a/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go @@ -175,7 +175,7 @@ type InterfaceVppAPI interface { AttachInterfaceToBond(ifIdx, bondIfIdx uint32, isPassive, isLongTimeout bool) error // DetachInterfaceFromBond removes interface slave status from any bond interfaces. DetachInterfaceFromBond(ifIdx uint32) error - // SetVLanTagRewrite sets VLan tag rewrite rule for given sub-interface + // SetVLanTagRewrite sets VLan tag rewrite rule for given sub-interface SetVLanTagRewrite(ifIdx uint32, subIf *interfaces.SubInterface) error } @@ -189,6 +189,8 @@ type InterfaceVppRead interface { DumpInterfaces() (map[uint32]*InterfaceDetails, error) // DumpInterfacesByType returns all VPP interfaces of the specified type DumpInterfacesByType(reqType interfaces.Interface_Type) (map[uint32]*InterfaceDetails, error) + // DumpInterface dumps specific interface. + DumpInterface(ifIdx uint32) (*InterfaceDetails, error) // GetInterfaceVrf reads VRF table to interface GetInterfaceVrf(ifIdx uint32) (vrfID uint32, err error) // GetInterfaceVrfIPv6 reads IPv6 VRF table to interface diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go index 1f89e22f74..4a95de10c2 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go @@ -16,6 +16,7 @@ package vpp1901 import ( "bytes" + "errors" "fmt" "net" "strings" @@ -47,6 +48,20 @@ func getMtu(vppMtu uint16) uint32 { return uint32(vppMtu) } +// DumpInterface dumps specific interface. +func (h *InterfaceVppHandler) DumpInterface(ifIdx uint32) (*vppcalls.InterfaceDetails, error) { + ifaces, err := h.DumpInterfaces() + if err != nil { + return nil, err + } + + iface, ok := ifaces[ifIdx] + if !ok { + return nil, errors.New("interface index not found in dump") + } + return iface, nil +} + // DumpInterfacesByType implements interface handler. func (h *InterfaceVppHandler) DumpInterfacesByType(reqType interfaces.Interface_Type) (map[uint32]*vppcalls.InterfaceDetails, error) { // Dump all diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go index e6f82cca2d..7ce358e3a4 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go @@ -17,6 +17,7 @@ package vpp1904 import ( "bytes" "encoding/hex" + "errors" "fmt" "net" "strings" @@ -46,6 +47,20 @@ func getMtu(vppMtu uint16) uint32 { return uint32(vppMtu) } +// DumpInterface dumps specific interface. +func (h *InterfaceVppHandler) DumpInterface(ifIdx uint32) (*vppcalls.InterfaceDetails, error) { + ifaces, err := h.DumpInterfaces() + if err != nil { + return nil, err + } + + iface, ok := ifaces[ifIdx] + if !ok { + return nil, errors.New("interface index not found in dump") + } + return iface, nil +} + // DumpInterfacesByType implements interface handler. func (h *InterfaceVppHandler) DumpInterfacesByType(reqType interfaces.Interface_Type) (map[uint32]*vppcalls.InterfaceDetails, error) { // Dump all diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1908/dump_interface_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1908/dump_interface_vppcalls.go index 67bd9e53cb..8694e01b13 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1908/dump_interface_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1908/dump_interface_vppcalls.go @@ -17,7 +17,9 @@ package vpp1908 import ( "bytes" "encoding/hex" + "errors" "fmt" + "math" "net" "strings" @@ -46,6 +48,22 @@ func getMtu(vppMtu uint16) uint32 { return uint32(vppMtu) } +// DumpInterface dumps specific interface. +func (h *InterfaceVppHandler) DumpInterface(ifIdx uint32) (*vppcalls.InterfaceDetails, error) { + var iface *vppcalls.InterfaceDetails + + ifaces, err := h.dumpInterfaces(ifIdx) + if err != nil { + return nil, err + } + iface, ok := ifaces[ifIdx] + if !ok { + return nil, errors.New("interface not found in dump") + } + + return iface, nil +} + // DumpInterfacesByType implements interface handler. func (h *InterfaceVppHandler) DumpInterfacesByType(reqType interfaces.Interface_Type) (map[uint32]*vppcalls.InterfaceDetails, error) { // Dump all @@ -63,12 +81,19 @@ func (h *InterfaceVppHandler) DumpInterfacesByType(reqType interfaces.Interface_ return ifs, nil } -func (h *InterfaceVppHandler) dumpInterfaces() (map[uint32]*vppcalls.InterfaceDetails, error) { +func (h *InterfaceVppHandler) dumpInterfaces(ifIdxs ...uint32) (map[uint32]*vppcalls.InterfaceDetails, error) { // map for the resulting interfaces ifs := make(map[uint32]*vppcalls.InterfaceDetails) + var ifIdx uint32 = math.MaxUint32 + if len(ifIdxs) > 0 { + ifIdx = ifIdxs[0] + } + // First, dump all interfaces to create initial data. - reqCtx := h.callsChannel.SendMultiRequest(&binapi_interface.SwInterfaceDump{}) + reqCtx := h.callsChannel.SendMultiRequest(&binapi_interface.SwInterfaceDump{ + SwIfIndex: binapi_interface.InterfaceIndex(ifIdx), + }) for { ifDetails := &binapi_interface.SwInterfaceDetails{} stop, err := reqCtx.ReceiveReply(ifDetails) diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1908/subif_vppcals_test.go b/plugins/vpp/ifplugin/vppcalls/vpp1908/subif_vppcalls_test.go similarity index 100% rename from plugins/vpp/ifplugin/vppcalls/vpp1908/subif_vppcals_test.go rename to plugins/vpp/ifplugin/vppcalls/vpp1908/subif_vppcalls_test.go diff --git a/tests/integration/vpp/000_initial_test.go b/tests/integration/vpp/000_initial_test.go index b502b264be..a9103eb2e2 100644 --- a/tests/integration/vpp/000_initial_test.go +++ b/tests/integration/vpp/000_initial_test.go @@ -24,25 +24,9 @@ func TestPing(t *testing.T) { ctx := setupVPP(t) defer ctx.teardownVPP() - h := vppcalls.CompatibleVpeHandler(ctx.Chan) + h := vppcalls.CompatibleVpeHandler(ctx.vppBinapi) if err := h.Ping(); err != nil { t.Fatalf("control ping failed: %v", err) } } - -func TestVersion(t *testing.T) { - ctx := setupVPP(t) - defer ctx.teardownVPP() - - h := vppcalls.CompatibleVpeHandler(ctx.Chan) - - info, err := h.GetVersionInfo() - if err != nil { - t.Fatalf("getting version info failed: %v", err) - } - t.Logf("version info: %+v", info) - if info.Version == "" { - t.Error("invalid version info") - } -} diff --git a/tests/integration/vpp/001_telemetry_test.go b/tests/integration/vpp/001_telemetry_test.go new file mode 100644 index 0000000000..237032a28e --- /dev/null +++ b/tests/integration/vpp/001_telemetry_test.go @@ -0,0 +1,68 @@ +// Copyright (c) 2019 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package vpp + +import ( + "context" + "testing" + + _ "github.com/ligato/vpp-agent/plugins/telemetry" + "github.com/ligato/vpp-agent/plugins/telemetry/vppcalls" +) + +func TestTelemetryNodeCounters(t *testing.T) { + ctx := setupVPP(t) + defer ctx.teardownVPP() + + if ctx.versionInfo.Release() <= "19.04" { + t.Skipf("SKIP for VPP %s", ctx.versionInfo.Release()) + } + + h := vppcalls.CompatibleTelemetryHandler(ctx.vppBinapi, ctx.vppStats) + + nodeCounters, err := h.GetNodeCounters(context.Background()) + if err != nil { + t.Fatalf("getting node counters failed: %v", err) + } + t.Logf("retrieved %d node counters", len(nodeCounters.Counters)) + if nodeCounters.Counters == nil { + t.Fatal("expected node counters, got nil") + } + if len(nodeCounters.Counters) == 0 { + t.Fatalf("expected node counters length > 0, got %v", len(nodeCounters.Counters)) + } +} + +func TestTelemetryMemory(t *testing.T) { + ctx := setupVPP(t) + defer ctx.teardownVPP() + + h := vppcalls.CompatibleTelemetryHandler(ctx.vppBinapi, ctx.vppStats) + + memStats, err := h.GetMemory(context.Background()) + if err != nil { + t.Fatalf("getting memory stats failed: %v", err) + } + t.Logf("retrieved memory stats: %+v", memStats) + if memStats.Threads == nil { + t.Fatal("expected memory stats, got nil") + } + if len(memStats.Threads) == 0 { + t.Fatalf("expected memory stats length > 0, got %v", len(memStats.Threads)) + } + if memStats.Threads[0].Total == 0 { + t.Errorf("expected memory stats - total > 0, got %v", memStats.Threads[0].Total) + } +} diff --git a/tests/integration/vpp/001_basic_test.go b/tests/integration/vpp/010_interfaces_test.go similarity index 51% rename from tests/integration/vpp/001_basic_test.go rename to tests/integration/vpp/010_interfaces_test.go index 0a6830b81e..910067325b 100644 --- a/tests/integration/vpp/001_basic_test.go +++ b/tests/integration/vpp/010_interfaces_test.go @@ -15,47 +15,83 @@ package vpp import ( - "net" "testing" "github.com/ligato/cn-infra/logging/logrus" vpp_interfaces "github.com/ligato/vpp-agent/api/models/vpp/interfaces" - vpp_l3 "github.com/ligato/vpp-agent/api/models/vpp/l3" _ "github.com/ligato/vpp-agent/plugins/vpp/ifplugin" - "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/ifaceidx" ifplugin_vppcalls "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/vppcalls" - _ "github.com/ligato/vpp-agent/plugins/vpp/l3plugin" - l3plugin_vppcalls "github.com/ligato/vpp-agent/plugins/vpp/l3plugin/vppcalls" - "github.com/ligato/vpp-agent/plugins/vpp/l3plugin/vrfidx" ) +func TestInterfaceDump(t *testing.T) { + ctx := setupVPP(t) + defer ctx.teardownVPP() + + h := ifplugin_vppcalls.CompatibleInterfaceVppHandler(ctx.vppBinapi, logrus.NewLogger("test")) + + ifIdx0, err := h.AddLoopbackInterface("loop0") + if err != nil { + t.Fatalf("creating loopback interface failed: %v", err) + } + t.Logf("loop0 index: %+v", ifIdx0) + + ifIdx, err := h.AddLoopbackInterface("loop1") + if err != nil { + t.Fatalf("creating loopback interface failed: %v", err) + } + t.Logf("loop1 index: %+v", ifIdx) + + ifaces, err := h.DumpInterfaces() + if err != nil { + t.Fatalf("dumping interfaces failed: %v", err) + } + if len(ifaces) != 3 { + t.Fatalf("expected 3 interfaces in dump, got %d", len(ifaces)) + } + + iface, err := h.DumpInterface(ifIdx) + if err != nil { + t.Fatalf("dumping interface failed: %v", err) + } + t.Logf("interface: %+v", iface.Interface) + if iface.Interface == nil { + t.Fatalf("expected interface, got nil") + } + if iface.Interface.Name != "loop1" { + t.Errorf("expected interface name to be loop1, got %v", iface.Interface.Name) + } + if iface.Interface.Type != vpp_interfaces.Interface_SOFTWARE_LOOPBACK { + t.Errorf("expected interface type to be loopback, got %v", iface.Interface.Type) + } +} + func TestLoopbackInterface(t *testing.T) { ctx := setupVPP(t) defer ctx.teardownVPP() - h := ifplugin_vppcalls.CompatibleInterfaceVppHandler(ctx.Chan, logrus.NewLogger("test")) + h := ifplugin_vppcalls.CompatibleInterfaceVppHandler(ctx.vppBinapi, logrus.NewLogger("test")) - index, err := h.AddLoopbackInterface("loop1") + ifIdx, err := h.AddLoopbackInterface("loop1") if err != nil { t.Fatalf("creating loopback interface failed: %v", err) } - t.Logf("loopback index: %+v", index) + t.Logf("loopback index: %+v", ifIdx) ifaces, err := h.DumpInterfaces() if err != nil { t.Fatalf("dumping interfaces failed: %v", err) } - iface, ok := ifaces[index] + iface, ok := ifaces[ifIdx] if !ok { t.Fatalf("loopback interface not found in dump") } t.Logf("interface: %+v", iface.Interface) if iface.Interface.Name != "loop1" { - t.Fatalf("expected interface name to be loop1, got %v", iface.Interface.Name) + t.Errorf("expected interface name to be loop1, got %v", iface.Interface.Name) } if iface.Interface.Type != vpp_interfaces.Interface_SOFTWARE_LOOPBACK { - t.Fatalf("expected interface type to be loopback, got %v", iface.Interface.Type) + t.Errorf("expected interface type to be loopback, got %v", iface.Interface.Type) } } @@ -63,70 +99,32 @@ func TestMemifInterface(t *testing.T) { ctx := setupVPP(t) defer ctx.teardownVPP() - h := ifplugin_vppcalls.CompatibleInterfaceVppHandler(ctx.Chan, logrus.NewLogger("test")) + h := ifplugin_vppcalls.CompatibleInterfaceVppHandler(ctx.vppBinapi, logrus.NewLogger("test")) - index, err := h.AddMemifInterface("memif1", &vpp_interfaces.MemifLink{ + ifIdx, err := h.AddMemifInterface("memif1", &vpp_interfaces.MemifLink{ Id: 1, Mode: vpp_interfaces.MemifLink_IP, Secret: "secret", Master: true, - }, 0 ) - + }, 0) if err != nil { t.Fatalf("creating memif interface failed: %v", err) } - t.Logf("memif index: %+v", index) + t.Logf("memif index: %+v", ifIdx) ifaces, err := h.DumpInterfaces() if err != nil { t.Fatalf("dumping interfaces failed: %v", err) } - iface, ok := ifaces[index] + iface, ok := ifaces[ifIdx] if !ok { t.Fatalf("Memif interface not found in dump") } t.Logf("interface: %+v", iface.Interface) if iface.Interface.Name != "memif1" { - t.Fatalf("expected interface name to be memif1, got %v", iface.Interface.Name) + t.Errorf("expected interface name to be memif1, got %v", iface.Interface.Name) } if iface.Interface.Type != vpp_interfaces.Interface_MEMIF { - t.Fatalf("expected interface type to be memif, got %v", iface.Interface.Type) - } -} - -func TestRoutes(t *testing.T) { - ctx := setupVPP(t) - defer ctx.teardownVPP() - - ifIndexes := ifaceidx.NewIfaceIndex(logrus.NewLogger("test-if"), "test-if") - vrfIndexes := vrfidx.NewVRFIndex(logrus.NewLogger("test-vrf"), "test-vrf") - vrfIndexes.Put("vrf1-ipv4", &vrfidx.VRFMetadata{Index: 0, Protocol: vpp_l3.VrfTable_IPV4}) - vrfIndexes.Put("vrf1-ipv6", &vrfidx.VRFMetadata{Index: 0, Protocol: vpp_l3.VrfTable_IPV6}) - - h := l3plugin_vppcalls.CompatibleL3VppHandler(ctx.Chan, ifIndexes, vrfIndexes, logrus.NewLogger("test")) - - routes, err := h.DumpRoutes() - if err != nil { - t.Fatalf("dumping routes failed: %v", err) - } - t.Logf("%d routes dumped", len(routes)) - - var hasIPv4, hasIPv6 bool - for _, route := range routes { - t.Logf(" - route: %+v", route.Route) - - ip, _, err := net.ParseCIDR(route.Route.DstNetwork) - if err != nil { - t.Fatalf("invalid dst network: %v", route.Route.DstNetwork) - } - if ip.To4() == nil { - hasIPv4 = true - } else { - hasIPv6 = true - } - } - - if !hasIPv4 || !hasIPv6 { - t.Fatalf("expected dump to contain both IPv4 and IPv6 routes") + t.Errorf("expected interface type to be memif, got %v", iface.Interface.Type) } } diff --git a/tests/integration/vpp/020_routes_test.go b/tests/integration/vpp/020_routes_test.go new file mode 100644 index 0000000000..85160657f5 --- /dev/null +++ b/tests/integration/vpp/020_routes_test.go @@ -0,0 +1,65 @@ +// Copyright (c) 2019 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package vpp + +import ( + "net" + "testing" + + "github.com/ligato/cn-infra/logging/logrus" + + vpp_l3 "github.com/ligato/vpp-agent/api/models/vpp/l3" + "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/ifaceidx" + _ "github.com/ligato/vpp-agent/plugins/vpp/l3plugin" + l3plugin_vppcalls "github.com/ligato/vpp-agent/plugins/vpp/l3plugin/vppcalls" + "github.com/ligato/vpp-agent/plugins/vpp/l3plugin/vrfidx" +) + +func TestRoutes(t *testing.T) { + ctx := setupVPP(t) + defer ctx.teardownVPP() + + ifIndexes := ifaceidx.NewIfaceIndex(logrus.NewLogger("test-if"), "test-if") + vrfIndexes := vrfidx.NewVRFIndex(logrus.NewLogger("test-vrf"), "test-vrf") + vrfIndexes.Put("vrf1-ipv4", &vrfidx.VRFMetadata{Index: 0, Protocol: vpp_l3.VrfTable_IPV4}) + vrfIndexes.Put("vrf1-ipv6", &vrfidx.VRFMetadata{Index: 0, Protocol: vpp_l3.VrfTable_IPV6}) + + h := l3plugin_vppcalls.CompatibleL3VppHandler(ctx.vppBinapi, ifIndexes, vrfIndexes, logrus.NewLogger("test")) + + routes, err := h.DumpRoutes() + if err != nil { + t.Fatalf("dumping routes failed: %v", err) + } + t.Logf("%d routes dumped", len(routes)) + + var hasIPv4, hasIPv6 bool + for _, route := range routes { + t.Logf(" - route: %+v", route.Route) + + ip, _, err := net.ParseCIDR(route.Route.DstNetwork) + if err != nil { + t.Fatalf("invalid dst network: %v", route.Route.DstNetwork) + } + if ip.To4() == nil { + hasIPv4 = true + } else { + hasIPv6 = true + } + } + + if !hasIPv4 || !hasIPv6 { + t.Fatalf("expected dump to contain both IPv4 and IPv6 routes") + } +} diff --git a/tests/integration/vpp/integration_test.go b/tests/integration/vpp/integration_test.go index 1271423629..1eb5e2b666 100644 --- a/tests/integration/vpp/integration_test.go +++ b/tests/integration/vpp/integration_test.go @@ -17,6 +17,7 @@ package vpp import ( "bytes" "flag" + "fmt" "log" "os" "os/exec" @@ -25,6 +26,7 @@ import ( "testing" "time" + "git.fd.io/govpp.git/adapter/statsclient" govppapi "git.fd.io/govpp.git/api" govppcore "git.fd.io/govpp.git/core" "github.com/mitchellh/go-ps" @@ -32,16 +34,47 @@ import ( "github.com/sirupsen/logrus" "github.com/ligato/vpp-agent/plugins/govppmux" + "github.com/ligato/vpp-agent/plugins/govppmux/vppcalls" ) var ( - vppPath = flag.String("vpp-path", "/usr/bin/vpp", "VPP program path") - vppConfig = flag.String("vpp-config", "/etc/vpp/vpp.conf", "VPP config file") + vppPath = flag.String("vpp-path", "/usr/bin/vpp", "VPP program path") + //vppConfig = flag.String("vpp-config", "/etc/vpp/vpp.conf", "VPP config file") vppSockAddr = flag.String("vpp-sock-addr", "", "VPP binapi socket address") debug = flag.Bool("debug", false, "Turn on debug mode.") ) +const ( + vppConnectRetries = 3 + vppConnectRetryDelay = time.Millisecond * 500 + vppBootDelay = time.Millisecond * 200 + vppTermDelay = time.Millisecond * 50 + vppExitTimeout = time.Second * 1 + + vppConf = ` + unix { + nodaemon + cli-listen /run/vpp/cli.sock + cli-no-pager + log /tmp/vpp.log + full-coredump + } + api-trace { + on + } + socksvr { + default + } + statseg { + default + per-node-counters on + } + plugins { + plugin dpdk_plugin.so { disable } + }` +) + func init() { log.SetFlags(log.Lmicroseconds | log.Lshortfile) flag.Parse() @@ -55,14 +88,17 @@ type testCtx struct { VPP *exec.Cmd stderr, stdout *bytes.Buffer Conn *govppcore.Connection - Chan govppapi.Channel + StatsConn *govppcore.StatsConnection + vppBinapi govppapi.Channel + vppStats govppapi.StatsProvider + vpe vppcalls.VpeVppAPI + versionInfo *vppcalls.VersionInfo } func setupVPP(t *testing.T) *testCtx { if os.Getenv("TRAVIS") != "" { t.Skip("skipping test for Travis") } - t.Logf("=== VPP setup ===") RegisterTestingT(t) @@ -72,15 +108,16 @@ func setupVPP(t *testing.T) *testCtx { t.Fatalf("listing processes failed: %v", err) } for _, process := range processes { - if strings.Contains(process.Executable(), "vpp") { - t.Logf("- found VPP process: %q (PID: %d)", process.Executable(), process.Pid()) + proc := process.Executable() + if strings.Contains(proc, "vpp") && process.Pid() != os.Getpid() { + t.Logf(" - found process: %+v", process) } - if process.Executable() == *vppPath || process.Executable() == "vpp" || process.Executable() == "vpp_main" { - t.Fatalf("VPP is already running, PID: %v", process.Pid()) + switch proc { + case *vppPath, "vpp", "vpp_main": + t.Fatalf("VPP is already running (PID: %v)", process.Pid()) } } - // remove binapi files from previous run var removeFile = func(path string) { if err := os.Remove(path); err == nil { t.Logf("removed file %q", path) @@ -88,86 +125,123 @@ func setupVPP(t *testing.T) *testCtx { t.Fatalf("removing file %q failed: %v", path, err) } } - removeFile("/run/vpp-api.sock") - - t.Logf("starting VPP process: %q", *vppPath) + // remove binapi files from previous run + removeFile(*vppSockAddr) + if err := os.Mkdir("/run/vpp", 0755); err != nil && !os.IsExist(err) { + t.Logf("mkdir failed: %v", err) + } - cmd := exec.Command(*vppPath, "-c", *vppConfig) var stderr, stdout bytes.Buffer + + cmd := exec.Command(*vppPath, vppConf) //"-c", *vppConfig) cmd.Stderr = &stderr cmd.Stdout = &stdout // ensure that process is killed when current process exits cmd.SysProcAttr = &syscall.SysProcAttr{Pdeathsig: syscall.SIGKILL} + t.Logf("starting VPP") + if err := cmd.Start(); err != nil { t.Fatalf("starting VPP failed: %v", err) } - t.Logf("VPP process started (PID: %v)", cmd.Process.Pid) + t.Logf("VPP start OK (PID: %v)", cmd.Process.Pid) adapter := govppmux.NewVppAdapter(*vppSockAddr, false) + + // wait until the socket is ready if err := adapter.WaitReady(); err != nil { t.Logf("WaitReady failed: %v", err) } + time.Sleep(vppBootDelay) - time.Sleep(time.Millisecond * 100) - - t.Logf("connecting to VPP..") - conn, err := govppcore.Connect(adapter) + connectRetry := func(retries int) (conn *govppcore.Connection, err error) { + for i := 1; i <= retries; i++ { + conn, err = govppcore.Connect(adapter) + if err != nil { + t.Logf("attempt #%d failed: %v, retrying in %v", i, err, vppConnectRetryDelay) + time.Sleep(vppConnectRetryDelay) + continue + } + return + } + return nil, fmt.Errorf("failed to connect after %d retries", retries) + } + conn, err := connectRetry(vppConnectRetries) if err != nil { - t.Logf("sending KILL signal to VPP") + t.Errorf("connecting to VPP failed: %v", err) if err := cmd.Process.Kill(); err != nil { t.Fatalf("killing VPP failed: %v", err) } if state, err := cmd.Process.Wait(); err != nil { - t.Logf("VPP process wait failed: %v", err) + t.Logf("VPP wait failed: %v", err) } else { - t.Logf("VPP killed: %v", state) + t.Logf("VPP wait OK: %v", state) } - t.Fatalf("connecting to VPP failed: %v", err) - } else { - t.Logf("connected to VPP successfully") + t.FailNow() } + t.Logf("VPP connect OK") ch, err := conn.NewAPIChannel() if err != nil { t.Fatalf("creating channel failed: %v", err) } + vpeHandler := vppcalls.CompatibleVpeHandler(ch) + versionInfo, err := vpeHandler.GetVersionInfo() + if err != nil { + t.Fatalf("getting version info failed: %v", err) + } + t.Logf("version info: %+v", versionInfo) + if versionInfo.Version == "" { + t.Error("invalid version") + } + + statsClient := statsclient.NewStatsClient("") + statsConn, err := govppcore.ConnectStats(statsClient) + if err != nil { + t.Fatalf("connecting to VPP stats API failed: %v", err) + } + + t.Logf("---------------") + return &testCtx{ - t: t, - VPP: cmd, - stderr: &stderr, - stdout: &stdout, - Conn: conn, - Chan: ch, + t: t, + versionInfo: versionInfo, + vpe: vpeHandler, + VPP: cmd, + stderr: &stderr, + stdout: &stdout, + Conn: conn, + vppBinapi: ch, + vppStats: statsConn, } } func (ctx *testCtx) teardownVPP() { - ctx.t.Logf("--- VPP teardown ---") + ctx.t.Logf("-----------------") // disconnect sometimes hangs done := make(chan struct{}) go func() { - ctx.Chan.Close() + ctx.StatsConn.Disconnect() + ctx.vppBinapi.Close() ctx.Conn.Disconnect() close(done) }() select { case <-done: - ctx.t.Logf("VPP disconnected") + ctx.t.Logf("VPP disconnect OK") + time.Sleep(vppTermDelay) - case <-time.After(time.Second * 1): + case <-time.After(vppExitTimeout): ctx.t.Logf("VPP disconnect timeout") } - time.Sleep(time.Millisecond * 100) - - ctx.t.Logf("sending SIGTERM to VPP") if err := ctx.VPP.Process.Signal(syscall.SIGTERM); err != nil { - ctx.t.Fatalf("sending SIGTERM signal to VPP failed: %v", err) + ctx.t.Fatalf("sending SIGTERM to VPP failed: %v", err) } + // wait until VPP exits exit := make(chan struct{}) go func() { if err := ctx.VPP.Wait(); err != nil { @@ -177,15 +251,13 @@ func (ctx *testCtx) teardownVPP() { }() select { case <-exit: - ctx.t.Logf("VPP exited") + ctx.t.Logf("VPP exit OK") - case <-time.After(time.Second * 1): + case <-time.After(vppExitTimeout): ctx.t.Logf("VPP exit timeout") - - ctx.t.Logf("sending SIGKILL to VPP") + ctx.t.Logf("sending SIGKILL to VPP..") if err := ctx.VPP.Process.Signal(syscall.SIGKILL); err != nil { - ctx.t.Fatalf("sending SIGKILL signal to VPP failed: %v", err) + ctx.t.Fatalf("sending SIGKILL to VPP failed: %v", err) } } - } diff --git a/tests/integration/vpp_integration.sh b/tests/integration/vpp_integration.sh index 9943ce7241..645bb8a38d 100755 --- a/tests/integration/vpp_integration.sh +++ b/tests/integration/vpp_integration.sh @@ -1,24 +1,46 @@ -#!/usr/bin/env bash +#!/bin/bash +set -eu -set -euo pipefail +# compile test +go test -c ./tests/integration/vpp -o ./tests/integration/vpp/vpp-integration.test +# start vpp image +cid=$(docker run -d -it \ + -v $(pwd)/tests/integration/vpp/vpp-integration.test:/vpp-integration.test:ro \ + --label vpp.integration.test="$*" \ + ${DOCKER_ARGS-} \ + "$VPP_IMG" bash) -function on_exit() { - echo "-> cleaning up" - docker stop -t 3 vpp-integration +on_exit() { + docker stop -t 2 "$cid" >/dev/null + docker rm "$cid" >/dev/null } -# compile vpp integration test -go test -v -c ./tests/integration/vpp +vppver=$(docker exec -i "$cid" dpkg-query -f '${Version}' -W vpp) -# start vpp image -docker run --rm --name vpp-integration -d -i -v $(pwd):/data:ro "${VPP_IMG}" bash -i trap 'on_exit' EXIT +echo "=============================================================" +echo -e " VPP Integration Test - \e[1;33m${vppver}\e[0m" +echo "=============================================================" + # run integration test -docker exec -it vpp-integration /data/vpp.test -test.v -vpp-config=/etc/vpp/startup.conf || { +if docker exec -i "$cid" /vpp-integration.test $*; then + echo >&2 "-------------------------------------------------------------" + echo >&2 -e " \e[32mPASSED\e[0m (took: ${SECONDS}s)" + echo >&2 "-------------------------------------------------------------" + exit 0 +else res=$? - echo >&2 "VPP integration tests FAILED!" - docker logs vpp-integration + echo >&2 "-------------------------------------------------------------" + echo >&2 -e " \e[31mFAILED!\e[0m (exit code: $res)" + echo >&2 "-------------------------------------------------------------" + + # dump container logs + logs=$(docker logs --tail 10 "$cid") + if [[ -n "$logs" ]]; then + echo >&2 -e "\e[1;30m$logs\e[0m" + fi + exit $res -} +fi diff --git a/vendor/git.fd.io/govpp.git/adapter/socketclient/socketclient.go b/vendor/git.fd.io/govpp.git/adapter/socketclient/socketclient.go index 96f23e6067..2144d24b37 100644 --- a/vendor/git.fd.io/govpp.git/adapter/socketclient/socketclient.go +++ b/vendor/git.fd.io/govpp.git/adapter/socketclient/socketclient.go @@ -40,6 +40,20 @@ const ( DefaultSocketName = adapter.DefaultBinapiSocket ) +const socketMissing = ` +------------------------------------------------------------ + VPP binary API socket file %s is missing! + + - is VPP running with socket for binapi enabled? + - is the correct socket name configured? + + To enable it add following section to your VPP config: + socksvr { + default + } +------------------------------------------------------------ +` + var ( // DefaultConnectTimeout is default timeout for connecting DefaultConnectTimeout = time.Second * 3 @@ -165,7 +179,13 @@ func (c *vppClient) SetMsgCallback(cb adapter.MsgCallback) { } func (c *vppClient) Connect() error { - Log.Debugf("Connecting to: %v", c.sockAddr) + // check if socket exists + if _, err := os.Stat(c.sockAddr); os.IsNotExist(err) { + fmt.Fprintf(os.Stderr, socketMissing, c.sockAddr) + return fmt.Errorf("VPP API socket file %s does not exist", c.sockAddr) + } else if err != nil { + return fmt.Errorf("VPP API socket error: %v", err) + } if err := c.connect(c.sockAddr); err != nil { return err @@ -212,12 +232,14 @@ func (c *vppClient) Disconnect() error { func (c *vppClient) connect(sockAddr string) error { addr := &net.UnixAddr{Name: sockAddr, Net: "unix"} + Log.Debugf("Connecting to: %v", c.sockAddr) + conn, err := net.DialUnix("unix", nil, addr) if err != nil { // we try different type of socket for backwards compatbility with VPP<=19.04 if strings.Contains(err.Error(), "wrong type for socket") { addr.Net = "unixpacket" - Log.Warnf("%s, retrying connect with type unixpacket", err) + Log.Debugf("%s, retrying connect with type unixpacket", err) conn, err = net.DialUnix("unixpacket", nil, addr) } if err != nil { diff --git a/vendor/git.fd.io/govpp.git/adapter/statsclient/stat_segment.go b/vendor/git.fd.io/govpp.git/adapter/statsclient/stat_segment.go index 1875f17ab2..e8d20b01b5 100644 --- a/vendor/git.fd.io/govpp.git/adapter/statsclient/stat_segment.go +++ b/vendor/git.fd.io/govpp.git/adapter/statsclient/stat_segment.go @@ -117,11 +117,11 @@ func (c *statSegment) connect(sockName string) error { header := c.readHeader() Log.Debugf("stat segment header: %+v", header) - // older VPP (19.04) did not have version in stat segment header + // older VPP (<=19.04) did not have version in stat segment header // we try to provide fallback support by skipping it in header if header.version > MaxVersion && header.inProgress > 1 && header.epoch == 0 { h := c.readHeaderOld() - Log.Warnf("statsclient: falling back to old stat segment version (VPP 19.04): %+v", h) + Log.Debugf("statsclient: falling back to old stat segment version (VPP <=19.04): %+v", h) c.oldHeader = true } diff --git a/vendor/git.fd.io/govpp.git/adapter/statsclient/statsclient.go b/vendor/git.fd.io/govpp.git/adapter/statsclient/statsclient.go index f715a70968..6381b9fd8a 100644 --- a/vendor/git.fd.io/govpp.git/adapter/statsclient/statsclient.go +++ b/vendor/git.fd.io/govpp.git/adapter/statsclient/statsclient.go @@ -27,6 +27,25 @@ import ( "git.fd.io/govpp.git/adapter" ) +const ( + // DefaultSocketName is default VPP stats socket file path. + DefaultSocketName = adapter.DefaultStatsSocket +) + +const socketMissing = ` +------------------------------------------------------------ + VPP stats socket file %s is missing! + + - is VPP running with stats segment enabled? + - is the correct socket name configured? + + To enable it add following section to your VPP config: + statseg { + default + } +------------------------------------------------------------ +` + var ( // Debug is global variable that determines debug mode Debug = os.Getenv("DEBUG_GOVPP_STATS") != "" @@ -55,29 +74,17 @@ type StatsClient struct { // NewStatsClient returns new VPP stats API client. func NewStatsClient(sockAddr string) *StatsClient { if sockAddr == "" { - sockAddr = adapter.DefaultStatsSocket + sockAddr = DefaultSocketName } return &StatsClient{ sockAddr: sockAddr, } } -const sockNotFoundWarn = `stats socket not found at: %s ------------------------------------------------------------- - VPP stats socket is missing! - Is VPP running with stats segment enabled? - - To enable it add following section to startup config: - statseg { - default - } ------------------------------------------------------------- -` - func (c *StatsClient) Connect() error { // check if socket exists if _, err := os.Stat(c.sockAddr); os.IsNotExist(err) { - Log.Warnf(sockNotFoundWarn, c.sockAddr) + fmt.Fprintf(os.Stderr, socketMissing, c.sockAddr) return fmt.Errorf("stats socket file %s does not exist", c.sockAddr) } else if err != nil { return fmt.Errorf("stats socket error: %v", err) diff --git a/vendor/git.fd.io/govpp.git/api/stats.go b/vendor/git.fd.io/govpp.git/api/stats.go index 0bf9908291..e254eae45d 100644 --- a/vendor/git.fd.io/govpp.git/api/stats.go +++ b/vendor/git.fd.io/govpp.git/api/stats.go @@ -1,3 +1,17 @@ +// Copyright (c) 2019 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package api // SystemStats represents global system statistics. From 367b5588ceaf16a649a3253aead5a11e9e049b4f Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Mon, 22 Jul 2019 18:54:18 +0200 Subject: [PATCH 04/10] Fix URL for VPP metrics in telemetry plugin (#1416) * Fix URL for VPP metrics in telemetry plugin Signed-off-by: Ondrej Fabry * Update Gopkg.lock --- Gopkg.lock | 1 - plugins/telemetry/metrics.go | 11 +---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 1989161da5..0cec8e7a72 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1074,7 +1074,6 @@ "github.com/pkg/errors", "github.com/pkg/profile", "github.com/prometheus/client_golang/prometheus", - "github.com/prometheus/client_golang/prometheus/promhttp", "github.com/sirupsen/logrus", "github.com/spf13/cobra", "github.com/unrolled/render", diff --git a/plugins/telemetry/metrics.go b/plugins/telemetry/metrics.go index ad5619f70e..333442c858 100644 --- a/plugins/telemetry/metrics.go +++ b/plugins/telemetry/metrics.go @@ -6,12 +6,11 @@ import ( "strconv" "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" ) const ( // Registry path for telemetry metrics - registryPath = "/metrics/vpp" + registryPath = "/metrics" vppMetricsNamespace = "vpp" @@ -147,14 +146,6 @@ type ifCounterStats struct { func (p *Plugin) registerPrometheus() error { p.Log.Debugf("registering prometheus registry path: %v", registryPath) - // Register vpp registry path - err := p.Prometheus.NewRegistry(registryPath, promhttp.HandlerOpts{ - ErrorHandling: promhttp.ContinueOnError, - }) - if err != nil { - return err - } - // Runtime metrics p.runtimeGaugeVecs = make(map[string]*prometheus.GaugeVec) p.runtimeStats = make(map[string]*runtimeStats) From ed83a66a22005ffc48153de4e780f602ff6707e3 Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Tue, 23 Jul 2019 11:32:11 +0200 Subject: [PATCH 05/10] Optimize interface state dump for specific interfaces (#1415) * Optimize interface state dump for specific interfaces - define env var for printing debug logs about interface states - extend interface state info in vppcalls for ifplugin - return error when loading config fails - minor improvements for VPP integration testing Signed-off-by: Ondrej Fabry * Remove obsolete function Signed-off-by: Ondrej Fabry --- plugins/vpp/ifplugin/config.go | 66 ++++++++ plugins/vpp/ifplugin/descriptor/link_state.go | 12 +- plugins/vpp/ifplugin/ifplugin.go | 63 ++------ plugins/vpp/ifplugin/interface_state.go | 134 ++++++---------- plugins/vpp/ifplugin/publish_state.go | 8 +- plugins/vpp/ifplugin/vppcalls/if_vppcalls.go | 13 +- .../vpp1901/dump_interface_vppcalls.go | 106 ++++++++----- .../vpp1904/dump_interface_vppcalls.go | 106 ++++++++----- .../vpp1908/dump_interface_vppcalls.go | 144 +++++++++++------- tests/integration/vpp/010_interfaces_test.go | 59 ++++--- tests/integration/vpp/integration_test.go | 48 +++--- 11 files changed, 448 insertions(+), 311 deletions(-) create mode 100644 plugins/vpp/ifplugin/config.go diff --git a/plugins/vpp/ifplugin/config.go b/plugins/vpp/ifplugin/config.go new file mode 100644 index 0000000000..54f1abd655 --- /dev/null +++ b/plugins/vpp/ifplugin/config.go @@ -0,0 +1,66 @@ +// Copyright (c) 2019 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ifplugin + +import ( + "os" + "time" +) + +var ( + // PeriodicPollingPeriod between statistics reads + // TODO should be configurable + PeriodicPollingPeriod = time.Second * 5 + + // StateUpdateDelay defines delay before dumping states + StateUpdateDelay = time.Second * 3 + + disableInterfaceStats = os.Getenv("DISABLE_INTERFACE_STATS") != "" + disableStatusPublishing = os.Getenv("DISABLE_STATUS_PUBLISHING") != "" +) + +// Config defines configuration for VPP ifplugin. +type Config struct { + MTU uint32 `json:"mtu"` + StatusPublishers []string `json:"status-publishers"` +} + +// DefaultConfig returns Config with default values. +func DefaultConfig() Config { + return Config{ + MTU: 0, + } +} + +func (p *IfPlugin) loadConfig() (*Config, error) { + cfg := DefaultConfig() + + found, err := p.Cfg.LoadValue(&cfg) + if err != nil { + return nil, err + } else if !found { + p.Log.Debugf("config %s not found", p.Cfg.GetConfigName()) + return nil, nil + } + p.Log.Debugf("config %s found: %+v", p.Cfg.GetConfigName(), cfg) + + // vppStatusPublishers can override state publishers from the configuration file. + if pubs := os.Getenv("VPP_STATUS_PUBLISHERS"); pubs != "" { + p.Log.Debugf("status publishers from env: %v", pubs) + cfg.StatusPublishers = append(cfg.StatusPublishers, pubs) + } + + return &cfg, err +} diff --git a/plugins/vpp/ifplugin/descriptor/link_state.go b/plugins/vpp/ifplugin/descriptor/link_state.go index f3724daa4e..70285fc338 100644 --- a/plugins/vpp/ifplugin/descriptor/link_state.go +++ b/plugins/vpp/ifplugin/descriptor/link_state.go @@ -57,9 +57,9 @@ func NewLinkStateDescriptor(kvscheduler kvs.KVScheduler, ifaceHandler vppcalls.I linkStates: make(map[string]bool), } return &kvs.KVDescriptor{ - Name: LinkStateDescriptorName, - KeySelector: descrCtx.IsInterfaceLinkStateKey, - Retrieve: descrCtx.Retrieve, + Name: LinkStateDescriptorName, + KeySelector: descrCtx.IsInterfaceLinkStateKey, + Retrieve: descrCtx.Retrieve, // Retrieve depends on the interface descriptor: interface index is used // to convert sw_if_index to logical interface name RetrieveDependencies: []string{InterfaceDescriptorName}, @@ -78,7 +78,7 @@ func (w *LinkStateDescriptor) IsInterfaceLinkStateKey(key string) bool { func (w *LinkStateDescriptor) Retrieve(correlate []kvs.KVWithMetadata) (values []kvs.KVWithMetadata, err error) { // TODO: avoid dumping interface details when it was already done in the interface // descriptor within the same Refresh (e.g. during full resync) - // - e.g. add context to allow sharing of information across Retrieve-s of the same Refresh + // - e.g. add context to allow sharing of information across Retrieve(s) of the same Refresh ifaceStates, err := w.ifaceHandler.DumpInterfaceStates() if err != nil { @@ -113,8 +113,6 @@ func (w *LinkStateDescriptor) UpdateLinkState(ifaceState *interfaces.InterfaceNo w.linkStatesMx.Lock() defer w.linkStatesMx.Unlock() - w.log.Debugf("Updating link state: %+v", ifaceState) - var notifs []kvs.KVWithMetadata operStatus := ifaceState.State.OperStatus @@ -152,4 +150,4 @@ func (w *LinkStateDescriptor) UpdateLinkState(ifaceState *interfaces.InterfaceNo w.log.Errorf("failed to send notifications to KVScheduler: %v", err) } } -} \ No newline at end of file +} diff --git a/plugins/vpp/ifplugin/ifplugin.go b/plugins/vpp/ifplugin/ifplugin.go index 08dbcf2343..c183bb3ba9 100644 --- a/plugins/vpp/ifplugin/ifplugin.go +++ b/plugins/vpp/ifplugin/ifplugin.go @@ -22,7 +22,6 @@ package ifplugin import ( "context" - "os" "sync" "time" @@ -49,22 +48,6 @@ import ( _ "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/vppcalls/vpp1908" ) -const ( - // vppStatusPublishersEnv is the name of the environment variable used to - // override state publishers from the configuration file. - vppStatusPublishersEnv = "VPP_STATUS_PUBLISHERS" -) - -var ( - // noopWriter (no operation writer) helps avoiding NIL pointer based segmentation fault. - // It is used as default if some dependency was not injected. - noopWriter = datasync.KVProtoWriters{} - - // noopWatcher (no operation watcher) helps avoiding NIL pointer based segmentation fault. - // It is used as default if some dependency was not injected. - noopWatcher = datasync.KVProtoWatchers{} -) - // IfPlugin configures VPP interfaces using GoVPP. type IfPlugin struct { Deps @@ -123,21 +106,15 @@ type Deps struct { PushNotification func(notification *vpp.Notification) } -// Config holds the vpp-plugin configuration. -type Config struct { - MTU uint32 `json:"mtu"` - StatusPublishers []string `json:"status-publishers"` -} - // Init loads configuration file and registers interface-related descriptors. -func (p *IfPlugin) Init() error { - var err error - +func (p *IfPlugin) Init() (err error) { // Create plugin context, save cancel function into the plugin handle. p.ctx, p.cancel = context.WithCancel(context.Background()) // Read config file and set all related fields - p.fromConfigFile() + if err := p.fromConfigFile(); err != nil { + return err + } // Fills nil dependencies with default values p.publishStats = p.PublishStatistics != nil || p.NotifyStates != nil @@ -330,11 +307,11 @@ func (p *IfPlugin) SetNotifyService(notify func(notification *vpp.Notification)) } // fromConfigFile loads plugin attributes from the configuration file. -func (p *IfPlugin) fromConfigFile() { +func (p *IfPlugin) fromConfigFile() error { config, err := p.loadConfig() if err != nil { p.Log.Errorf("Error reading %v config file: %v", p.PluginName, err) - return + return err } if config != nil { publishers := datasync.KVProtoWriters{} @@ -353,28 +330,18 @@ func (p *IfPlugin) fromConfigFile() { p.Log.Infof("Default MTU set to %v", p.defaultMtu) } } + return nil } -// loadConfig loads configuration file. -func (p *IfPlugin) loadConfig() (*Config, error) { - config := &Config{} - - found, err := p.Cfg.LoadValue(config) - if err != nil { - return nil, err - } else if !found { - p.Log.Debugf("%v config not found", p.PluginName) - return nil, nil - } - p.Log.Debugf("%v config found: %+v", p.PluginName, config) - - if pubs := os.Getenv(vppStatusPublishersEnv); pubs != "" { - p.Log.Debugf("status publishers from env: %v", pubs) - config.StatusPublishers = append(config.StatusPublishers, pubs) - } +var ( + // noopWriter (no operation writer) helps avoiding NIL pointer based segmentation fault. + // It is used as default if some dependency was not injected. + noopWriter = datasync.KVProtoWriters{} - return config, err -} + // noopWatcher (no operation watcher) helps avoiding NIL pointer based segmentation fault. + // It is used as default if some dependency was not injected. + noopWatcher = datasync.KVProtoWatchers{} +) // fixNilPointers sets noopWriter & nooWatcher for nil dependencies. func (p *IfPlugin) fixNilPointers() { diff --git a/plugins/vpp/ifplugin/interface_state.go b/plugins/vpp/ifplugin/interface_state.go index b231f10afa..3c3d522bb9 100644 --- a/plugins/vpp/ifplugin/interface_state.go +++ b/plugins/vpp/ifplugin/interface_state.go @@ -32,15 +32,7 @@ import ( ) var ( - // PeriodicPollingPeriod between statistics reads - // TODO should be configurable - PeriodicPollingPeriod = time.Second * 5 - - // StateUpdateDelay defines delay before dumping states - StateUpdateDelay = time.Second * 3 - - disableInterfaceStats = os.Getenv("DISABLE_INTERFACE_STATS") != "" - disableStatusPublishing = os.Getenv("DISABLE_STATUS_PUBLISHING") != "" + debugIfStates = os.Getenv("DEBUG_IFSTATES") != "" ) // InterfaceStateUpdater holds state data of all VPP interfaces. @@ -51,8 +43,9 @@ type InterfaceStateUpdater struct { swIfIndexes ifaceidx.IfaceMetadataIndex publishIfState func(notification *intf.InterfaceNotification) - access sync.Mutex // lock for the state data map - ifState map[uint32]*intf.InterfaceState // swIfIndex to state data map + // access guards access to ifState map + access sync.Mutex + ifState map[uint32]*intf.InterfaceState // swIfIndex goVppMux govppmux.StatsAPI @@ -73,9 +66,11 @@ type InterfaceStateUpdater struct { } // Init members (channels, maps...) and start go routines -func (c *InterfaceStateUpdater) Init(ctx context.Context, logger logging.PluginLogger, kvScheduler kvs.KVScheduler, +func (c *InterfaceStateUpdater) Init(ctx context.Context, + logger logging.PluginLogger, kvScheduler kvs.KVScheduler, goVppMux govppmux.StatsAPI, swIfIndexes ifaceidx.IfaceMetadataIndex, - publishIfState func(notification *intf.InterfaceNotification), readCounters bool) (err error) { + publishIfState func(*intf.InterfaceNotification), readCounters bool, +) (err error) { // Logger c.log = logger.NewLogger("if-state") @@ -256,24 +251,27 @@ func (c *InterfaceStateUpdater) doUpdatesIfStateDetails() { // we dont want to lock during potentionally long dump call c.access.Unlock() - c.log.Debugf("running update for interface state details (%d)", len(c.ifsForUpdate)) + c.log.Debugf("updating interface states for %d interfaces", len(c.ifsForUpdate)) - ifaces, err := c.ifHandler.DumpInterfaces() + var ifIdxs []uint32 + c.access.Lock() + for ifIdx := range c.ifsForUpdate { + ifIdxs = append(ifIdxs, ifIdx) + } + // clear interfaces for update + c.ifsForUpdate = make(map[uint32]struct{}) + c.access.Unlock() + + ifaces, err := c.ifHandler.DumpInterfaceStates(ifIdxs...) if err != nil { - c.log.Warnf("dump interfaces failed: %v", err) + c.log.Warnf("dumping interface states failed: %v", err) return } c.access.Lock() for _, ifaceDetails := range ifaces { - if _, ok := c.ifsForUpdate[ifaceDetails.Meta.SwIfIndex]; !ok { - // not interface for update - continue - } c.updateIfStateDetails(ifaceDetails) } - // clear interfaces for update - c.ifsForUpdate = make(map[uint32]struct{}) c.access.Unlock() } @@ -309,7 +307,6 @@ func (c *InterfaceStateUpdater) doInterfaceStatsRead() { // processInterfaceStatEntry fills state data for every registered interface and publishes them func (c *InterfaceStateUpdater) processInterfaceStatEntry(ifCounters govppapi.InterfaceCounters) { - ifState, found := c.getIfStateDataWLookup(ifCounters.InterfaceIndex) if !found { return @@ -331,12 +328,13 @@ func (c *InterfaceStateUpdater) processInterfaceStatEntry(ifCounters govppapi.In } c.publishIfState(&intf.InterfaceNotification{ - Type: intf.InterfaceNotification_COUNTERS, State: ifState}) + Type: intf.InterfaceNotification_COUNTERS, + State: ifState, + }) } // processIfStateEvent process a VPP state event notification. func (c *InterfaceStateUpdater) processIfStateEvent(notif *vppcalls.InterfaceEvent) { - c.access.Lock() defer c.access.Unlock() @@ -347,26 +345,28 @@ func (c *InterfaceStateUpdater) processIfStateEvent(notif *vppcalls.InterfaceEve if !found { return } - c.log.Debugf("Interface state notification for %s (idx: %d): %+v", - ifState.Name, ifState.IfIndex, notif) + + if debugIfStates { + c.log.Debugf("Interface state notification for %s (idx: %d): %+v", + ifState.Name, ifState.IfIndex, notif) + } // store data in ETCD c.publishIfState(&intf.InterfaceNotification{ - Type: intf.InterfaceNotification_UPDOWN, State: ifState}) + Type: intf.InterfaceNotification_UPDOWN, + State: ifState, + }) } // getIfStateData returns interface state data structure for the specified interface index and interface name. // NOTE: plugin.ifStateData needs to be locked when calling this function! func (c *InterfaceStateUpdater) getIfStateData(swIfIndex uint32, ifName string) (*intf.InterfaceState, bool) { - ifState, ok := c.ifState[swIfIndex] - // check also if the provided logical name c the same as the one associated // with swIfIndex, because swIfIndexes might be reused if ok && ifState.Name == ifName { return ifState, true } - return nil, false } @@ -396,8 +396,8 @@ func (c *InterfaceStateUpdater) getIfStateDataWLookup(ifIdx uint32) (*intf.Inter // updateIfStateFlags updates the interface state data in memory from provided VPP flags message and returns updated state data. // NOTE: plugin.ifStateData needs to be locked when calling this function! func (c *InterfaceStateUpdater) updateIfStateFlags(vppMsg *vppcalls.InterfaceEvent) ( - iface *intf.InterfaceState, found bool) { - + iface *intf.InterfaceState, found bool, +) { ifState, found := c.getIfStateDataWLookup(vppMsg.SwIfIndex) if !found { return nil, false @@ -422,71 +422,26 @@ func (c *InterfaceStateUpdater) updateIfStateFlags(vppMsg *vppcalls.InterfaceEve return ifState, true } -const megabit = 1000000 // One megabit in bytes - // updateIfStateDetails updates the interface state data in memory from provided VPP details message. -func (c *InterfaceStateUpdater) updateIfStateDetails(ifDetails *vppcalls.InterfaceDetails) { - - ifState, found := c.getIfStateDataWLookup(ifDetails.Meta.SwIfIndex) +func (c *InterfaceStateUpdater) updateIfStateDetails(ifDetails *vppcalls.InterfaceState) { + ifState, found := c.getIfStateDataWLookup(ifDetails.SwIfIndex) if !found { return } - ifState.InternalName = ifDetails.Meta.InternalName + ifState.InternalName = ifDetails.InternalName + ifState.PhysAddress = ifDetails.PhysAddress.String() + ifState.AdminStatus = ifDetails.AdminState + ifState.OperStatus = ifDetails.LinkState + ifState.Speed = ifDetails.LinkSpeed + ifState.Duplex = ifDetails.LinkDuplex + ifState.Mtu = uint32(ifDetails.LinkMTU) - if ifDetails.Meta.AdminState == 1 { - ifState.AdminStatus = intf.InterfaceState_UP - } else if ifDetails.Meta.AdminState == 0 { - ifState.AdminStatus = intf.InterfaceState_DOWN - } else { - ifState.AdminStatus = intf.InterfaceState_UNKNOWN_STATUS - } - - if ifDetails.Meta.LinkState == 1 { - ifState.OperStatus = intf.InterfaceState_UP - } else if ifDetails.Meta.LinkState == 0 { - ifState.OperStatus = intf.InterfaceState_DOWN - } else { - ifState.OperStatus = intf.InterfaceState_UNKNOWN_STATUS - } - - ifState.PhysAddress = ifDetails.Interface.PhysAddress - - ifState.Mtu = uint32(ifDetails.Meta.LinkMTU) - - switch ifDetails.Meta.LinkSpeed { - case 1: - ifState.Speed = 10 * megabit // 10M - case 2: - ifState.Speed = 100 * megabit // 100M - case 4: - ifState.Speed = 1000 * megabit // 1G - case 8: - ifState.Speed = 10000 * megabit // 10G - case 16: - ifState.Speed = 40000 * megabit // 40G - case 32: - ifState.Speed = 100000 * megabit // 100G - default: - ifState.Speed = 0 - } - - switch ifDetails.Meta.LinkSpeed { - case 1: - ifState.Duplex = intf.InterfaceState_HALF - case 2: - ifState.Duplex = intf.InterfaceState_FULL - default: - ifState.Duplex = intf.InterfaceState_UNKNOWN_DUPLEX - } - - c.publishIfState(&intf.InterfaceNotification{ - Type: intf.InterfaceNotification_UNKNOWN, State: ifState}) + c.publishIfState(&intf.InterfaceNotification{State: ifState}) } // setIfStateDeleted marks the interface as deleted in the state data structure in memory. func (c *InterfaceStateUpdater) setIfStateDeleted(swIfIndex uint32, ifName string) { - c.access.Lock() defer c.access.Unlock() @@ -499,6 +454,5 @@ func (c *InterfaceStateUpdater) setIfStateDeleted(swIfIndex uint32, ifName strin ifState.LastChange = time.Now().Unix() // this can be post-processed by multiple plugins - c.publishIfState(&intf.InterfaceNotification{ - Type: intf.InterfaceNotification_UNKNOWN, State: ifState}) + c.publishIfState(&intf.InterfaceNotification{State: ifState}) } diff --git a/plugins/vpp/ifplugin/publish_state.go b/plugins/vpp/ifplugin/publish_state.go index 34df2ded1c..273ff8aa08 100644 --- a/plugins/vpp/ifplugin/publish_state.go +++ b/plugins/vpp/ifplugin/publish_state.go @@ -99,7 +99,9 @@ func (p *IfPlugin) publishIfStateEvents() { p.publishLock.Lock() key := interfaces.InterfaceStateKey(ifState.State.Name) - p.Log.Debugf("Publishing interface state: %+v", ifState) + if debugIfStates { + p.Log.Debugf("Publishing interface state: %+v", ifState) + } if p.PublishStatistics != nil { err := p.PublishStatistics.Put(key, ifState.State) @@ -134,7 +136,9 @@ func (p *IfPlugin) publishIfStateEvents() { if ifState.Type == interfaces.InterfaceNotification_UPDOWN || ifState.State.OperStatus == interfaces.InterfaceState_DELETED { - + if debugIfStates { + p.Log.Debugf("Updating link state: %+v", ifState) + } p.linkStateDescriptor.UpdateLinkState(ifState) if p.PushNotification != nil { p.PushNotification(&vpp.Notification{ diff --git a/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go index 9acdd70185..de2205a7dd 100644 --- a/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/if_vppcalls.go @@ -89,8 +89,15 @@ type Lease struct { // InterfaceState is a helper function grouping interface state data. type InterfaceState struct { + SwIfIndex uint32 + InternalName string + PhysAddress net.HardwareAddr + AdminState interfaces.InterfaceState_Status LinkState interfaces.InterfaceState_Status + LinkDuplex interfaces.InterfaceState_Duplex + LinkSpeed uint64 + LinkMTU uint16 } // InterfaceVppAPI provides methods for creating and managing interface plugin @@ -189,8 +196,8 @@ type InterfaceVppRead interface { DumpInterfaces() (map[uint32]*InterfaceDetails, error) // DumpInterfacesByType returns all VPP interfaces of the specified type DumpInterfacesByType(reqType interfaces.Interface_Type) (map[uint32]*InterfaceDetails, error) - // DumpInterface dumps specific interface. - DumpInterface(ifIdx uint32) (*InterfaceDetails, error) + // DumpInterfaceStates dumps link and administrative state of every interface. + DumpInterfaceStates(ifIdxs ...uint32) (map[uint32]*InterfaceState, error) // GetInterfaceVrf reads VRF table to interface GetInterfaceVrf(ifIdx uint32) (vrfID uint32, err error) // GetInterfaceVrfIPv6 reads IPv6 VRF table to interface @@ -199,8 +206,6 @@ type InterfaceVppRead interface { DumpMemifSocketDetails() (map[string]uint32, error) // DumpDhcpClients dumps DHCP-related information for all interfaces. DumpDhcpClients() (map[uint32]*Dhcp, error) - // DumpInterfaceStates dumps link and administrative state of every interface. - DumpInterfaceStates() (map[uint32]*InterfaceState, error) // WatchInterfaceEvents starts watching for interface events. WatchInterfaceEvents(ch chan<- *InterfaceEvent) error // WatchDHCPLeases starts watching for DHCP leases. diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go index 4a95de10c2..f085bf9d1a 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1901/dump_interface_vppcalls.go @@ -16,7 +16,6 @@ package vpp1901 import ( "bytes" - "errors" "fmt" "net" "strings" @@ -48,20 +47,6 @@ func getMtu(vppMtu uint16) uint32 { return uint32(vppMtu) } -// DumpInterface dumps specific interface. -func (h *InterfaceVppHandler) DumpInterface(ifIdx uint32) (*vppcalls.InterfaceDetails, error) { - ifaces, err := h.DumpInterfaces() - if err != nil { - return nil, err - } - - iface, ok := ifaces[ifIdx] - if !ok { - return nil, errors.New("interface index not found in dump") - } - return iface, nil -} - // DumpInterfacesByType implements interface handler. func (h *InterfaceVppHandler) DumpInterfacesByType(reqType interfaces.Interface_Type) (map[uint32]*vppcalls.InterfaceDetails, error) { // Dump all @@ -203,7 +188,7 @@ func (h *InterfaceVppHandler) DumpInterfaces() (map[uint32]*vppcalls.InterfaceDe ifData.Meta.SwIfIndex, err) } ifData.Meta.VrfIPv6 = ipv6Vrf - if isIPv6If, err := h.isIpv6Interface(ifData.Interface); err != nil { + if isIPv6If, err := isIpv6Interface(ifData.Interface); err != nil { return ifs, err } else if isIPv6If { ifData.Interface.Vrf = ipv6Vrf @@ -352,9 +337,14 @@ func (h *InterfaceVppHandler) DumpDhcpClients() (map[uint32]*vppcalls.Dhcp, erro } // DumpInterfaceStates dumps link and administrative state of every interface. -func (h *InterfaceVppHandler) DumpInterfaceStates() (map[uint32]*vppcalls.InterfaceState, error) { +func (h *InterfaceVppHandler) DumpInterfaceStates(ifIdxs ...uint32) (map[uint32]*vppcalls.InterfaceState, error) { ifs := make(map[uint32]*vppcalls.InterfaceState) + // initialize the requested interface indexes to nil + for _, ifIdx := range ifIdxs { + ifs[ifIdx] = nil + } + reqCtx := h.callsChannel.SendMultiRequest(&binapi_interface.SwInterfaceDump{}) for { ifDetails := &binapi_interface.SwInterfaceDetails{} @@ -366,32 +356,80 @@ func (h *InterfaceVppHandler) DumpInterfaceStates() (map[uint32]*vppcalls.Interf return nil, fmt.Errorf("failed to dump interface: %v", err) } - ifaceState := &vppcalls.InterfaceState{} - switch ifDetails.AdminUpDown { - case 0: - ifaceState.AdminState = interfaces.InterfaceState_DOWN - case 1: - ifaceState.AdminState = interfaces.InterfaceState_UP - default: - ifaceState.AdminState = interfaces.InterfaceState_UNKNOWN_STATUS + // when dumping specific list of interfaces.. + if len(ifIdxs) != 0 { + // and current ifIdx was not initialized.. + if _, ok := ifs[ifDetails.SwIfIndex]; !ok { + // then skip processing it to omit it from results + continue + } } - switch ifDetails.LinkUpDown { - case 0: - ifaceState.LinkState = interfaces.InterfaceState_DOWN - case 1: - ifaceState.LinkState = interfaces.InterfaceState_UP - default: - ifaceState.LinkState = interfaces.InterfaceState_UNKNOWN_STATUS + + physAddr := make(net.HardwareAddr, ifDetails.L2AddressLength) + copy(physAddr, ifDetails.L2Address[:]) + + ifaceState := vppcalls.InterfaceState{ + SwIfIndex: ifDetails.SwIfIndex, + InternalName: cleanString(ifDetails.InterfaceName), + PhysAddress: physAddr, + AdminState: toInterfaceStatus(ifDetails.AdminUpDown), + LinkState: toInterfaceStatus(ifDetails.LinkUpDown), + LinkDuplex: toLinkDuplex(ifDetails.LinkDuplex), + LinkSpeed: toLinkSpeed(ifDetails.LinkSpeed), + LinkMTU: ifDetails.LinkMtu, } - ifs[ifDetails.SwIfIndex] = ifaceState + ifs[ifDetails.SwIfIndex] = &ifaceState } return ifs, nil } +func toInterfaceStatus(upDown uint8) interfaces.InterfaceState_Status { + switch upDown { + case 0: + return interfaces.InterfaceState_DOWN + case 1: + return interfaces.InterfaceState_UP + default: + return interfaces.InterfaceState_UNKNOWN_STATUS + } +} + +func toLinkDuplex(duplex uint8) interfaces.InterfaceState_Duplex { + switch duplex { + case 1: + return interfaces.InterfaceState_HALF + case 2: + return interfaces.InterfaceState_FULL + default: + return interfaces.InterfaceState_UNKNOWN_DUPLEX + } +} + +const megabit = 1000000 // one megabit in bytes + +func toLinkSpeed(speed uint32) uint64 { + switch speed { + case 1: + return 10 * megabit // 10M + case 2: + return 100 * megabit // 100M + case 4: + return 1000 * megabit // 1G + case 8: + return 10000 * megabit // 10G + case 16: + return 40000 * megabit // 40G + case 32: + return 100000 * megabit // 100G + default: + return 0 + } +} + // Returns true if given interface contains at least one IPv6 address. For VxLAN, source and destination // addresses are also checked -func (h *InterfaceVppHandler) isIpv6Interface(iface *interfaces.Interface) (bool, error) { +func isIpv6Interface(iface *interfaces.Interface) (bool, error) { if iface.Type == interfaces.Interface_VXLAN_TUNNEL && iface.GetVxlan() != nil { if ipAddress := net.ParseIP(iface.GetVxlan().SrcAddress); ipAddress.To4() == nil { return true, nil diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go index 7ce358e3a4..896d1dd1c1 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1904/dump_interface_vppcalls.go @@ -17,7 +17,6 @@ package vpp1904 import ( "bytes" "encoding/hex" - "errors" "fmt" "net" "strings" @@ -47,20 +46,6 @@ func getMtu(vppMtu uint16) uint32 { return uint32(vppMtu) } -// DumpInterface dumps specific interface. -func (h *InterfaceVppHandler) DumpInterface(ifIdx uint32) (*vppcalls.InterfaceDetails, error) { - ifaces, err := h.DumpInterfaces() - if err != nil { - return nil, err - } - - iface, ok := ifaces[ifIdx] - if !ok { - return nil, errors.New("interface index not found in dump") - } - return iface, nil -} - // DumpInterfacesByType implements interface handler. func (h *InterfaceVppHandler) DumpInterfacesByType(reqType interfaces.Interface_Type) (map[uint32]*vppcalls.InterfaceDetails, error) { // Dump all @@ -202,7 +187,7 @@ func (h *InterfaceVppHandler) DumpInterfaces() (map[uint32]*vppcalls.InterfaceDe ifData.Meta.SwIfIndex, err) } ifData.Meta.VrfIPv6 = ipv6Vrf - if isIPv6If, err := h.isIpv6Interface(ifData.Interface); err != nil { + if isIPv6If, err := isIpv6Interface(ifData.Interface); err != nil { return ifs, err } else if isIPv6If { ifData.Interface.Vrf = ipv6Vrf @@ -351,9 +336,14 @@ func (h *InterfaceVppHandler) DumpDhcpClients() (map[uint32]*vppcalls.Dhcp, erro } // DumpInterfaceStates dumps link and administrative state of every interface. -func (h *InterfaceVppHandler) DumpInterfaceStates() (map[uint32]*vppcalls.InterfaceState, error) { +func (h *InterfaceVppHandler) DumpInterfaceStates(ifIdxs ...uint32) (map[uint32]*vppcalls.InterfaceState, error) { ifs := make(map[uint32]*vppcalls.InterfaceState) + // initialize the requested interface indexes to nil + for _, ifIdx := range ifIdxs { + ifs[ifIdx] = nil + } + reqCtx := h.callsChannel.SendMultiRequest(&binapi_interface.SwInterfaceDump{}) for { ifDetails := &binapi_interface.SwInterfaceDetails{} @@ -365,32 +355,80 @@ func (h *InterfaceVppHandler) DumpInterfaceStates() (map[uint32]*vppcalls.Interf return nil, fmt.Errorf("failed to dump interface: %v", err) } - ifaceState := &vppcalls.InterfaceState{} - switch ifDetails.AdminUpDown { - case 0: - ifaceState.AdminState = interfaces.InterfaceState_DOWN - case 1: - ifaceState.AdminState = interfaces.InterfaceState_UP - default: - ifaceState.AdminState = interfaces.InterfaceState_UNKNOWN_STATUS + // when dumping specific list of interfaces.. + if len(ifIdxs) != 0 { + // and current ifIdx was not initialized.. + if _, ok := ifs[ifDetails.SwIfIndex]; !ok { + // then skip processing it to omit it from results + continue + } } - switch ifDetails.LinkUpDown { - case 0: - ifaceState.LinkState = interfaces.InterfaceState_DOWN - case 1: - ifaceState.LinkState = interfaces.InterfaceState_UP - default: - ifaceState.LinkState = interfaces.InterfaceState_UNKNOWN_STATUS + + physAddr := make(net.HardwareAddr, ifDetails.L2AddressLength) + copy(physAddr, ifDetails.L2Address[:]) + + ifaceState := vppcalls.InterfaceState{ + SwIfIndex: ifDetails.SwIfIndex, + InternalName: cleanString(ifDetails.InterfaceName), + PhysAddress: physAddr, + AdminState: toInterfaceStatus(ifDetails.AdminUpDown), + LinkState: toInterfaceStatus(ifDetails.LinkUpDown), + LinkDuplex: toLinkDuplex(ifDetails.LinkDuplex), + LinkSpeed: toLinkSpeed(ifDetails.LinkSpeed), + LinkMTU: ifDetails.LinkMtu, } - ifs[ifDetails.SwIfIndex] = ifaceState + ifs[ifDetails.SwIfIndex] = &ifaceState } return ifs, nil } +func toInterfaceStatus(upDown uint8) interfaces.InterfaceState_Status { + switch upDown { + case 0: + return interfaces.InterfaceState_DOWN + case 1: + return interfaces.InterfaceState_UP + default: + return interfaces.InterfaceState_UNKNOWN_STATUS + } +} + +func toLinkDuplex(duplex uint8) interfaces.InterfaceState_Duplex { + switch duplex { + case 1: + return interfaces.InterfaceState_HALF + case 2: + return interfaces.InterfaceState_FULL + default: + return interfaces.InterfaceState_UNKNOWN_DUPLEX + } +} + +const megabit = 1000000 // one megabit in bytes + +func toLinkSpeed(speed uint32) uint64 { + switch speed { + case 1: + return 10 * megabit // 10M + case 2: + return 100 * megabit // 100M + case 4: + return 1000 * megabit // 1G + case 8: + return 10000 * megabit // 10G + case 16: + return 40000 * megabit // 40G + case 32: + return 100000 * megabit // 100G + default: + return 0 + } +} + // Returns true if given interface contains at least one IPv6 address. For VxLAN, source and destination // addresses are also checked -func (h *InterfaceVppHandler) isIpv6Interface(iface *interfaces.Interface) (bool, error) { +func isIpv6Interface(iface *interfaces.Interface) (bool, error) { if iface.Type == interfaces.Interface_VXLAN_TUNNEL && iface.GetVxlan() != nil { if ipAddress := net.ParseIP(iface.GetVxlan().SrcAddress); ipAddress.To4() == nil { return true, nil diff --git a/plugins/vpp/ifplugin/vppcalls/vpp1908/dump_interface_vppcalls.go b/plugins/vpp/ifplugin/vppcalls/vpp1908/dump_interface_vppcalls.go index 8694e01b13..123dca2402 100644 --- a/plugins/vpp/ifplugin/vppcalls/vpp1908/dump_interface_vppcalls.go +++ b/plugins/vpp/ifplugin/vppcalls/vpp1908/dump_interface_vppcalls.go @@ -17,9 +17,7 @@ package vpp1908 import ( "bytes" "encoding/hex" - "errors" "fmt" - "math" "net" "strings" @@ -37,6 +35,11 @@ import ( "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/vppcalls" ) +const ( + // allInterfaces defines unspecified interface index + allInterfaces = ^uint32(0) +) + // Default VPP MTU value const defaultVPPMtu = 9216 @@ -48,22 +51,6 @@ func getMtu(vppMtu uint16) uint32 { return uint32(vppMtu) } -// DumpInterface dumps specific interface. -func (h *InterfaceVppHandler) DumpInterface(ifIdx uint32) (*vppcalls.InterfaceDetails, error) { - var iface *vppcalls.InterfaceDetails - - ifaces, err := h.dumpInterfaces(ifIdx) - if err != nil { - return nil, err - } - iface, ok := ifaces[ifIdx] - if !ok { - return nil, errors.New("interface not found in dump") - } - - return iface, nil -} - // DumpInterfacesByType implements interface handler. func (h *InterfaceVppHandler) DumpInterfacesByType(reqType interfaces.Interface_Type) (map[uint32]*vppcalls.InterfaceDetails, error) { // Dump all @@ -85,11 +72,10 @@ func (h *InterfaceVppHandler) dumpInterfaces(ifIdxs ...uint32) (map[uint32]*vppc // map for the resulting interfaces ifs := make(map[uint32]*vppcalls.InterfaceDetails) - var ifIdx uint32 = math.MaxUint32 + ifIdx := allInterfaces if len(ifIdxs) > 0 { ifIdx = ifIdxs[0] } - // First, dump all interfaces to create initial data. reqCtx := h.callsChannel.SendMultiRequest(&binapi_interface.SwInterfaceDump{ SwIfIndex: binapi_interface.InterfaceIndex(ifIdx), @@ -98,7 +84,7 @@ func (h *InterfaceVppHandler) dumpInterfaces(ifIdxs ...uint32) (map[uint32]*vppc ifDetails := &binapi_interface.SwInterfaceDetails{} stop, err := reqCtx.ReceiveReply(ifDetails) if stop { - break // Break from the loop. + break } if err != nil { return nil, fmt.Errorf("failed to dump interface: %v", err) @@ -109,8 +95,9 @@ func (h *InterfaceVppHandler) dumpInterfaces(ifIdxs ...uint32) (map[uint32]*vppc details := &vppcalls.InterfaceDetails{ Interface: &interfaces.Interface{ - Name: cleanString(ifDetails.Tag), - Type: guessInterfaceType(ifaceName), // the type may be amended later by further dumps + Name: cleanString(ifDetails.Tag), + // the type may be amended later by further dumps + Type: guessInterfaceType(ifaceName), Enabled: ifDetails.AdminUpDown > 0, PhysAddress: net.HardwareAddr(ifDetails.L2Address[:ifDetails.L2AddressLength]).String(), Mtu: getMtu(ifDetails.LinkMtu), @@ -212,7 +199,7 @@ func (h *InterfaceVppHandler) DumpInterfaces() (map[uint32]*vppcalls.InterfaceDe ifData.Meta.SwIfIndex, err) } ifData.Meta.VrfIPv6 = ipv6Vrf - if isIPv6If, err := h.isIpv6Interface(ifData.Interface); err != nil { + if isIPv6If, err := isIpv6Interface(ifData.Interface); err != nil { return ifs, err } else if isIPv6If { ifData.Interface.Vrf = ipv6Vrf @@ -361,46 +348,93 @@ func (h *InterfaceVppHandler) DumpDhcpClients() (map[uint32]*vppcalls.Dhcp, erro } // DumpInterfaceStates dumps link and administrative state of every interface. -func (h *InterfaceVppHandler) DumpInterfaceStates() (map[uint32]*vppcalls.InterfaceState, error) { +func (h *InterfaceVppHandler) DumpInterfaceStates(ifIdxs ...uint32) (map[uint32]*vppcalls.InterfaceState, error) { + // Dump all interface states if not specified. + if len(ifIdxs) == 0 { + ifIdxs = []uint32{allInterfaces} + } + ifs := make(map[uint32]*vppcalls.InterfaceState) + for _, ifIdx := range ifIdxs { + reqCtx := h.callsChannel.SendMultiRequest(&binapi_interface.SwInterfaceDump{ + SwIfIndex: binapi_interface.InterfaceIndex(ifIdx), + }) + for { + ifDetails := &binapi_interface.SwInterfaceDetails{} + stop, err := reqCtx.ReceiveReply(ifDetails) + if stop { + break // Break from the loop. + } + if err != nil { + return nil, fmt.Errorf("failed to dump interface states: %v", err) + } - reqCtx := h.callsChannel.SendMultiRequest(&binapi_interface.SwInterfaceDump{}) - for { - ifDetails := &binapi_interface.SwInterfaceDetails{} - stop, err := reqCtx.ReceiveReply(ifDetails) - if stop { - break // Break from the loop. - } - if err != nil { - return nil, fmt.Errorf("failed to dump interface: %v", err) - } + physAddr := make(net.HardwareAddr, ifDetails.L2AddressLength) + copy(physAddr, ifDetails.L2Address[:]) - ifaceState := &vppcalls.InterfaceState{} - switch ifDetails.AdminUpDown { - case 0: - ifaceState.AdminState = interfaces.InterfaceState_DOWN - case 1: - ifaceState.AdminState = interfaces.InterfaceState_UP - default: - ifaceState.AdminState = interfaces.InterfaceState_UNKNOWN_STATUS - } - switch ifDetails.LinkUpDown { - case 0: - ifaceState.LinkState = interfaces.InterfaceState_DOWN - case 1: - ifaceState.LinkState = interfaces.InterfaceState_UP - default: - ifaceState.LinkState = interfaces.InterfaceState_UNKNOWN_STATUS + ifaceState := vppcalls.InterfaceState{ + SwIfIndex: ifDetails.SwIfIndex, + InternalName: cleanString(ifDetails.InterfaceName), + PhysAddress: physAddr, + AdminState: toInterfaceStatus(ifDetails.AdminUpDown), + LinkState: toInterfaceStatus(ifDetails.LinkUpDown), + LinkDuplex: toLinkDuplex(ifDetails.LinkDuplex), + LinkSpeed: toLinkSpeed(ifDetails.LinkSpeed), + LinkMTU: ifDetails.LinkMtu, + } + ifs[ifDetails.SwIfIndex] = &ifaceState } - ifs[ifDetails.SwIfIndex] = ifaceState } return ifs, nil } +func toInterfaceStatus(upDown uint8) interfaces.InterfaceState_Status { + switch upDown { + case 0: + return interfaces.InterfaceState_DOWN + case 1: + return interfaces.InterfaceState_UP + default: + return interfaces.InterfaceState_UNKNOWN_STATUS + } +} + +func toLinkDuplex(duplex uint8) interfaces.InterfaceState_Duplex { + switch duplex { + case 1: + return interfaces.InterfaceState_HALF + case 2: + return interfaces.InterfaceState_FULL + default: + return interfaces.InterfaceState_UNKNOWN_DUPLEX + } +} + +const megabit = 1000000 // one megabit in bytes + +func toLinkSpeed(speed uint32) uint64 { + switch speed { + case 1: + return 10 * megabit // 10M + case 2: + return 100 * megabit // 100M + case 4: + return 1000 * megabit // 1G + case 8: + return 10000 * megabit // 10G + case 16: + return 40000 * megabit // 40G + case 32: + return 100000 * megabit // 100G + default: + return 0 + } +} + // Returns true if given interface contains at least one IPv6 address. For VxLAN, source and destination // addresses are also checked -func (h *InterfaceVppHandler) isIpv6Interface(iface *interfaces.Interface) (bool, error) { +func isIpv6Interface(iface *interfaces.Interface) (bool, error) { if iface.Type == interfaces.Interface_VXLAN_TUNNEL && iface.GetVxlan() != nil { if ipAddress := net.ParseIP(iface.GetVxlan().SrcAddress); ipAddress.To4() == nil { return true, nil @@ -556,7 +590,9 @@ func (h *InterfaceVppHandler) dumpTapDetails(ifs map[uint32]*vppcalls.InterfaceD // dumpVxlanDetails dumps VXLAN interface details from VPP and fills them into the provided interface map. func (h *InterfaceVppHandler) dumpVxlanDetails(ifs map[uint32]*vppcalls.InterfaceDetails) error { - reqCtx := h.callsChannel.SendMultiRequest(&vxlan.VxlanTunnelDump{SwIfIndex: ^uint32(0)}) + reqCtx := h.callsChannel.SendMultiRequest(&vxlan.VxlanTunnelDump{ + SwIfIndex: ^uint32(0), + }) for { vxlanDetails := &vxlan.VxlanTunnelDetails{} stop, err := reqCtx.ReceiveReply(vxlanDetails) diff --git a/tests/integration/vpp/010_interfaces_test.go b/tests/integration/vpp/010_interfaces_test.go index 910067325b..dd809600bc 100644 --- a/tests/integration/vpp/010_interfaces_test.go +++ b/tests/integration/vpp/010_interfaces_test.go @@ -24,7 +24,7 @@ import ( ifplugin_vppcalls "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/vppcalls" ) -func TestInterfaceDump(t *testing.T) { +func TestInterfaceDumpState(t *testing.T) { ctx := setupVPP(t) defer ctx.teardownVPP() @@ -42,27 +42,29 @@ func TestInterfaceDump(t *testing.T) { } t.Logf("loop1 index: %+v", ifIdx) - ifaces, err := h.DumpInterfaces() + ifaces, err := h.DumpInterfaceStates() if err != nil { - t.Fatalf("dumping interfaces failed: %v", err) + t.Fatalf("dumping interface states failed: %v", err) } if len(ifaces) != 3 { - t.Fatalf("expected 3 interfaces in dump, got %d", len(ifaces)) + t.Errorf("expected 3 interface states in dump, got: %d", len(ifaces)) } - iface, err := h.DumpInterface(ifIdx) + ifaces, err = h.DumpInterfaceStates(ifIdx) if err != nil { - t.Fatalf("dumping interface failed: %v", err) + t.Fatalf("dumping interface states failed: %v", err) } - t.Logf("interface: %+v", iface.Interface) - if iface.Interface == nil { - t.Fatalf("expected interface, got nil") + iface := ifaces[ifIdx] + t.Logf("interface state: %+v", iface) + + if iface == nil { + t.Fatalf("expected interface, got: nil") } - if iface.Interface.Name != "loop1" { - t.Errorf("expected interface name to be loop1, got %v", iface.Interface.Name) + if iface.InternalName != "loop1" { + t.Errorf("expected interface internal name to be loop1, got: %v", iface.InternalName) } - if iface.Interface.Type != vpp_interfaces.Interface_SOFTWARE_LOOPBACK { - t.Errorf("expected interface type to be loopback, got %v", iface.Interface.Type) + if len(iface.PhysAddress) == 0 { + t.Errorf("expected interface phys address to not be empty, got: %q", iface.PhysAddress) } } @@ -87,11 +89,21 @@ func TestLoopbackInterface(t *testing.T) { t.Fatalf("loopback interface not found in dump") } t.Logf("interface: %+v", iface.Interface) + if iface.Interface.Name != "loop1" { - t.Errorf("expected interface name to be loop1, got %v", iface.Interface.Name) + t.Errorf("expected interface name to be loop1, got: %v", iface.Interface.Name) + } + if iface.Interface.PhysAddress == "" { + t.Errorf("expected interface phys address to not be empty, got: %v", iface.Interface.PhysAddress) + } + if iface.Interface.Enabled == true { + t.Errorf("expected interface to not be enabled") } if iface.Interface.Type != vpp_interfaces.Interface_SOFTWARE_LOOPBACK { - t.Errorf("expected interface type to be loopback, got %v", iface.Interface.Type) + t.Errorf("expected interface type to be SOFTWARE_LOOPBACK, got: %v", iface.Interface.Type) + } + if iface.Interface.Link != nil { + t.Errorf("expected interface link to be nil, got: %T", iface.Interface.Link) } } @@ -103,7 +115,7 @@ func TestMemifInterface(t *testing.T) { ifIdx, err := h.AddMemifInterface("memif1", &vpp_interfaces.MemifLink{ Id: 1, - Mode: vpp_interfaces.MemifLink_IP, + Mode: vpp_interfaces.MemifLink_ETHERNET, Secret: "secret", Master: true, }, 0) @@ -121,10 +133,21 @@ func TestMemifInterface(t *testing.T) { t.Fatalf("Memif interface not found in dump") } t.Logf("interface: %+v", iface.Interface) + if iface.Interface.Name != "memif1" { - t.Errorf("expected interface name to be memif1, got %v", iface.Interface.Name) + t.Errorf("expected interface name to be memif1, got: %v", iface.Interface.Name) } if iface.Interface.Type != vpp_interfaces.Interface_MEMIF { - t.Errorf("expected interface type to be memif, got %v", iface.Interface.Type) + t.Errorf("expected interface type to be memif, got: %v", iface.Interface.Type) + } + link, ok := iface.Interface.Link.(*vpp_interfaces.Interface_Memif) + if !ok { + t.Fatalf("expected interface link to be memif, got: %T", iface.Interface.Link) + } + if link.Memif.Id != 1 { + t.Errorf("expected memif ID to be 1, got: %v", link.Memif.Id) + } + if link.Memif.Mode != vpp_interfaces.MemifLink_ETHERNET { + t.Errorf("expected memif mode to be ETHERNET, got: %v", link.Memif.Mode) } } diff --git a/tests/integration/vpp/integration_test.go b/tests/integration/vpp/integration_test.go index 1eb5e2b666..1cf4e15662 100644 --- a/tests/integration/vpp/integration_test.go +++ b/tests/integration/vpp/integration_test.go @@ -26,6 +26,7 @@ import ( "testing" "time" + "git.fd.io/govpp.git/adapter/socketclient" "git.fd.io/govpp.git/adapter/statsclient" govppapi "git.fd.io/govpp.git/api" govppcore "git.fd.io/govpp.git/core" @@ -33,13 +34,12 @@ import ( . "github.com/onsi/gomega" "github.com/sirupsen/logrus" - "github.com/ligato/vpp-agent/plugins/govppmux" "github.com/ligato/vpp-agent/plugins/govppmux/vppcalls" ) var ( - vppPath = flag.String("vpp-path", "/usr/bin/vpp", "VPP program path") - //vppConfig = flag.String("vpp-config", "/etc/vpp/vpp.conf", "VPP config file") + vppPath = flag.String("vpp-path", "/usr/bin/vpp", "VPP program path") + vppConfig = flag.String("vpp-config", "", "VPP config file") vppSockAddr = flag.String("vpp-sock-addr", "", "VPP binapi socket address") debug = flag.Bool("debug", false, "Turn on debug mode.") @@ -133,20 +133,23 @@ func setupVPP(t *testing.T) *testCtx { var stderr, stdout bytes.Buffer - cmd := exec.Command(*vppPath, vppConf) //"-c", *vppConfig) - cmd.Stderr = &stderr - cmd.Stdout = &stdout + vppCmd := exec.Command(*vppPath) + if *vppConfig != "" { + vppCmd.Args = append(vppCmd.Args, "-c", *vppConfig) + } else { + vppCmd.Args = append(vppCmd.Args, vppConf) + } + vppCmd.Stderr = &stderr + vppCmd.Stdout = &stdout // ensure that process is killed when current process exits - cmd.SysProcAttr = &syscall.SysProcAttr{Pdeathsig: syscall.SIGKILL} - - t.Logf("starting VPP") - - if err := cmd.Start(); err != nil { + vppCmd.SysProcAttr = &syscall.SysProcAttr{Pdeathsig: syscall.SIGKILL} + if err := vppCmd.Start(); err != nil { t.Fatalf("starting VPP failed: %v", err) } - t.Logf("VPP start OK (PID: %v)", cmd.Process.Pid) + vppPID := uint32(vppCmd.Process.Pid) + t.Logf("VPP start OK (PID: %v)", vppPID) - adapter := govppmux.NewVppAdapter(*vppSockAddr, false) + adapter := socketclient.NewVppClient(*vppSockAddr) // wait until the socket is ready if err := adapter.WaitReady(); err != nil { @@ -169,17 +172,16 @@ func setupVPP(t *testing.T) *testCtx { conn, err := connectRetry(vppConnectRetries) if err != nil { t.Errorf("connecting to VPP failed: %v", err) - if err := cmd.Process.Kill(); err != nil { + if err := vppCmd.Process.Kill(); err != nil { t.Fatalf("killing VPP failed: %v", err) } - if state, err := cmd.Process.Wait(); err != nil { + if state, err := vppCmd.Process.Wait(); err != nil { t.Logf("VPP wait failed: %v", err) } else { t.Logf("VPP wait OK: %v", state) } t.FailNow() } - t.Logf("VPP connect OK") ch, err := conn.NewAPIChannel() if err != nil { @@ -191,9 +193,16 @@ func setupVPP(t *testing.T) *testCtx { if err != nil { t.Fatalf("getting version info failed: %v", err) } - t.Logf("version info: %+v", versionInfo) + t.Logf("VPP version: %v", versionInfo.Version) if versionInfo.Version == "" { - t.Error("invalid version") + t.Fatal("expected VPP version to not be empty") + } + vpeInfo, err := vpeHandler.GetVpeInfo() + if err != nil { + t.Fatalf("getting vpe info failed: %v", err) + } + if vpeInfo.PID != vppPID { + t.Fatalf("expected VPP PID to be %v, got %v", vppPID, vpeInfo.PID) } statsClient := statsclient.NewStatsClient("") @@ -208,7 +217,7 @@ func setupVPP(t *testing.T) *testCtx { t: t, versionInfo: versionInfo, vpe: vpeHandler, - VPP: cmd, + VPP: vppCmd, stderr: &stderr, stdout: &stdout, Conn: conn, @@ -230,7 +239,6 @@ func (ctx *testCtx) teardownVPP() { }() select { case <-done: - ctx.t.Logf("VPP disconnect OK") time.Sleep(vppTermDelay) case <-time.After(vppExitTimeout): From 483f36e587b25ca7a29b19525922320fde867534 Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Wed, 24 Jul 2019 13:11:50 +0200 Subject: [PATCH 06/10] Add option for skipping metrics in telemetry plugin (#1417) Signed-off-by: Ondrej Fabry --- plugins/telemetry/config.go | 10 + plugins/telemetry/metrics.go | 310 ++++++++++++++++--------------- plugins/telemetry/telemetry.conf | 4 + plugins/telemetry/telemetry.go | 13 +- 4 files changed, 180 insertions(+), 157 deletions(-) diff --git a/plugins/telemetry/config.go b/plugins/telemetry/config.go index 1ef38375f6..f3796e51f9 100644 --- a/plugins/telemetry/config.go +++ b/plugins/telemetry/config.go @@ -16,12 +16,22 @@ package telemetry import "time" +const ( + // default period between updates + defaultUpdatePeriod = time.Second * 30 + // minimum period between updates + minimumUpdatePeriod = time.Second * 1 +) + // Config file representation for telemetry plugin type Config struct { // Custom polling interval, default value is 30s PollingInterval time.Duration `json:"polling-interval"` // Allows to disable plugin Disabled bool `json:"disabled"` + // Skip collecting some of the metrics: + // runtime, memory, buffers, nodes, interfaces + Skipped []string `json:"skipped"` } func defaultConfig() *Config { diff --git a/plugins/telemetry/metrics.go b/plugins/telemetry/metrics.go index 333442c858..8db159ec45 100644 --- a/plugins/telemetry/metrics.go +++ b/plugins/telemetry/metrics.go @@ -318,29 +318,70 @@ func (p *Plugin) registerPrometheus() error { func (p *Plugin) updatePrometheus(ctx context.Context) { p.tracef("running update") - // Update runtime - runtimeInfo, err := p.handler.GetRuntimeInfo(ctx) - if err != nil { - p.Log.Errorf("GetRuntimeInfo failed: %v", err) - } else { - p.tracef("runtime info: %+v", runtimeInfo) - for _, thread := range runtimeInfo.GetThreads() { - for _, item := range thread.Items { - stats, ok := p.runtimeStats[item.Name] + if !p.skipped[runtimeMetricsNamespace] { + // Update runtime + runtimeInfo, err := p.handler.GetRuntimeInfo(ctx) + if err != nil { + p.Log.Errorf("GetRuntimeInfo failed: %v", err) + } else { + p.tracef("runtime info: %+v", runtimeInfo) + for _, thread := range runtimeInfo.GetThreads() { + for _, item := range thread.Items { + stats, ok := p.runtimeStats[item.Name] + if !ok { + stats = &runtimeStats{ + threadID: thread.ID, + threadName: thread.Name, + itemName: item.Name, + metrics: map[string]prometheus.Gauge{}, + } + + // add gauges with corresponding labels into vectors + for k, vec := range p.runtimeGaugeVecs { + stats.metrics[k], err = vec.GetMetricWith(prometheus.Labels{ + runtimeItemLabel: item.Name, + runtimeThreadLabel: thread.Name, + runtimeThreadIDLabel: strconv.Itoa(int(thread.ID)), + }) + if err != nil { + p.Log.Error(err) + } + } + } + + stats.metrics[runtimeCallsMetric].Set(float64(item.Calls)) + stats.metrics[runtimeVectorsMetric].Set(float64(item.Vectors)) + stats.metrics[runtimeSuspendsMetric].Set(float64(item.Suspends)) + stats.metrics[runtimeClocksMetric].Set(item.Clocks) + stats.metrics[runtimeVectorsPerCallMetric].Set(item.VectorsPerCall) + } + } + } + } + + if !p.skipped[buffersMetricsNamespace] { + // Update buffers + buffersInfo, err := p.handler.GetBuffersInfo(ctx) + if err != nil { + p.Log.Errorf("GetBuffersInfo failed: %v", err) + } else { + p.tracef("buffers info: %+v", buffersInfo) + for _, item := range buffersInfo.GetItems() { + stats, ok := p.buffersStats[item.Name] if !ok { - stats = &runtimeStats{ - threadID: thread.ID, - threadName: thread.Name, - itemName: item.Name, - metrics: map[string]prometheus.Gauge{}, + stats = &buffersStats{ + threadID: item.ThreadID, + itemName: item.Name, + itemIndex: item.Index, + metrics: map[string]prometheus.Gauge{}, } // add gauges with corresponding labels into vectors - for k, vec := range p.runtimeGaugeVecs { + for k, vec := range p.buffersGaugeVecs { stats.metrics[k], err = vec.GetMetricWith(prometheus.Labels{ - runtimeItemLabel: item.Name, - runtimeThreadLabel: thread.Name, - runtimeThreadIDLabel: strconv.Itoa(int(thread.ID)), + buffersThreadIDLabel: strconv.Itoa(int(item.ThreadID)), + buffersItemLabel: item.Name, + buffersIndexLabel: strconv.Itoa(int(item.Index)), }) if err != nil { p.Log.Error(err) @@ -348,162 +389,131 @@ func (p *Plugin) updatePrometheus(ctx context.Context) { } } - stats.metrics[runtimeCallsMetric].Set(float64(item.Calls)) - stats.metrics[runtimeVectorsMetric].Set(float64(item.Vectors)) - stats.metrics[runtimeSuspendsMetric].Set(float64(item.Suspends)) - stats.metrics[runtimeClocksMetric].Set(item.Clocks) - stats.metrics[runtimeVectorsPerCallMetric].Set(item.VectorsPerCall) + stats.metrics[buffersSizeMetric].Set(float64(item.Size)) + stats.metrics[buffersAllocMetric].Set(float64(item.Alloc)) + stats.metrics[buffersFreeMetric].Set(float64(item.Free)) + stats.metrics[buffersNumAllocMetric].Set(float64(item.NumAlloc)) + stats.metrics[buffersNumFreeMetric].Set(float64(item.NumFree)) } } } - // Update buffers - buffersInfo, err := p.handler.GetBuffersInfo(ctx) - if err != nil { - p.Log.Errorf("GetBuffersInfo failed: %v", err) - } else { - p.tracef("buffers info: %+v", buffersInfo) - for _, item := range buffersInfo.GetItems() { - stats, ok := p.buffersStats[item.Name] - if !ok { - stats = &buffersStats{ - threadID: item.ThreadID, - itemName: item.Name, - itemIndex: item.Index, - metrics: map[string]prometheus.Gauge{}, - } - - // add gauges with corresponding labels into vectors - for k, vec := range p.buffersGaugeVecs { - stats.metrics[k], err = vec.GetMetricWith(prometheus.Labels{ - buffersThreadIDLabel: strconv.Itoa(int(item.ThreadID)), - buffersItemLabel: item.Name, - buffersIndexLabel: strconv.Itoa(int(item.Index)), - }) - if err != nil { - p.Log.Error(err) + if !p.skipped[memoryMetricsNamespace] { + // Update memory + memoryInfo, err := p.handler.GetMemory(ctx) + if err != nil { + p.Log.Errorf("GetMemory failed: %v", err) + } else { + p.tracef("memory info: %+v", memoryInfo) + for _, thread := range memoryInfo.GetThreads() { + stats, ok := p.memoryStats[thread.Name] + if !ok { + stats = &memoryStats{ + threadName: thread.Name, + threadID: thread.ID, + metrics: map[string]prometheus.Gauge{}, } - } - } - - stats.metrics[buffersSizeMetric].Set(float64(item.Size)) - stats.metrics[buffersAllocMetric].Set(float64(item.Alloc)) - stats.metrics[buffersFreeMetric].Set(float64(item.Free)) - stats.metrics[buffersNumAllocMetric].Set(float64(item.NumAlloc)) - stats.metrics[buffersNumFreeMetric].Set(float64(item.NumFree)) - } - } - - // Update memory - memoryInfo, err := p.handler.GetMemory(ctx) - if err != nil { - p.Log.Errorf("GetMemory failed: %v", err) - } else { - p.tracef("memory info: %+v", memoryInfo) - for _, thread := range memoryInfo.GetThreads() { - stats, ok := p.memoryStats[thread.Name] - if !ok { - stats = &memoryStats{ - threadName: thread.Name, - threadID: thread.ID, - metrics: map[string]prometheus.Gauge{}, - } - // add gauges with corresponding labels into vectors - for k, vec := range p.memoryGaugeVecs { - stats.metrics[k], err = vec.GetMetricWith(prometheus.Labels{ - memoryThreadLabel: thread.Name, - memoryThreadIDLabel: strconv.Itoa(int(thread.ID)), - }) - if err != nil { - p.Log.Error(err) + // add gauges with corresponding labels into vectors + for k, vec := range p.memoryGaugeVecs { + stats.metrics[k], err = vec.GetMetricWith(prometheus.Labels{ + memoryThreadLabel: thread.Name, + memoryThreadIDLabel: strconv.Itoa(int(thread.ID)), + }) + if err != nil { + p.Log.Error(err) + } } } - } - stats.metrics[memoryObjectsMetric].Set(float64(thread.Objects)) - stats.metrics[memoryUsedMetric].Set(float64(thread.Used)) - stats.metrics[memoryTotalMetric].Set(float64(thread.Total)) - stats.metrics[memoryFreeMetric].Set(float64(thread.Free)) - stats.metrics[memoryReclaimedMetric].Set(float64(thread.Reclaimed)) - stats.metrics[memoryOverheadMetric].Set(float64(thread.Overhead)) - stats.metrics[memorySizeMetric].Set(float64(thread.Size)) - stats.metrics[memoryPagesMetric].Set(float64(thread.Pages)) + stats.metrics[memoryObjectsMetric].Set(float64(thread.Objects)) + stats.metrics[memoryUsedMetric].Set(float64(thread.Used)) + stats.metrics[memoryTotalMetric].Set(float64(thread.Total)) + stats.metrics[memoryFreeMetric].Set(float64(thread.Free)) + stats.metrics[memoryReclaimedMetric].Set(float64(thread.Reclaimed)) + stats.metrics[memoryOverheadMetric].Set(float64(thread.Overhead)) + stats.metrics[memorySizeMetric].Set(float64(thread.Size)) + stats.metrics[memoryPagesMetric].Set(float64(thread.Pages)) + } } } - // Update node counters - nodeCountersInfo, err := p.handler.GetNodeCounters(ctx) - if err != nil { - p.Log.Errorf("GetNodeCounters failed: %v", err) - } else { - p.tracef("node counters info: %+v", nodeCountersInfo) - for _, item := range nodeCountersInfo.GetCounters() { - stats, ok := p.nodeCounterStats[item.Name] - if !ok { - stats = &nodeCounterStats{ - itemName: item.Name, - metrics: map[string]prometheus.Gauge{}, - } + if !p.skipped[nodeMetricsNamespace] { + // Update node counters + nodeCountersInfo, err := p.handler.GetNodeCounters(ctx) + if err != nil { + p.Log.Errorf("GetNodeCounters failed: %v", err) + } else { + p.tracef("node counters info: %+v", nodeCountersInfo) + for _, item := range nodeCountersInfo.GetCounters() { + stats, ok := p.nodeCounterStats[item.Name] + if !ok { + stats = &nodeCounterStats{ + itemName: item.Name, + metrics: map[string]prometheus.Gauge{}, + } - // add gauges with corresponding labels into vectors - for k, vec := range p.nodeCounterGaugeVecs { - stats.metrics[k], err = vec.GetMetricWith(prometheus.Labels{ - nodeCounterItemLabel: item.Node, - nodeCounterReasonLabel: item.Name, - }) - if err != nil { - p.Log.Error(err) + // add gauges with corresponding labels into vectors + for k, vec := range p.nodeCounterGaugeVecs { + stats.metrics[k], err = vec.GetMetricWith(prometheus.Labels{ + nodeCounterItemLabel: item.Node, + nodeCounterReasonLabel: item.Name, + }) + if err != nil { + p.Log.Error(err) + } } } - } - stats.metrics[nodeCounterCounterMetric].Set(float64(item.Value)) + stats.metrics[nodeCounterCounterMetric].Set(float64(item.Value)) + } } } - // Update interface counters - ifStats, err := p.handler.GetInterfaceStats(ctx) - if err != nil { - p.Log.Errorf("GetInterfaceStats failed: %v", err) - return - } else { - p.tracef("interface stats: %+v", ifStats) - if ifStats == nil { + if !p.skipped[ifMetricsNamespace] { + // Update interface counters + ifStats, err := p.handler.GetInterfaceStats(ctx) + if err != nil { + p.Log.Errorf("GetInterfaceStats failed: %v", err) return - } - for _, item := range ifStats.Interfaces { - stats, ok := p.ifCounterStats[item.InterfaceName] - if !ok { - stats = &ifCounterStats{ - name: item.InterfaceName, - metrics: map[string]prometheus.Gauge{}, - } + } else { + p.tracef("interface stats: %+v", ifStats) + if ifStats == nil { + return + } + for _, item := range ifStats.Interfaces { + stats, ok := p.ifCounterStats[item.InterfaceName] + if !ok { + stats = &ifCounterStats{ + name: item.InterfaceName, + metrics: map[string]prometheus.Gauge{}, + } - // add gauges with corresponding labels into vectors - for k, vec := range p.ifCounterGaugeVecs { - stats.metrics[k], err = vec.GetMetricWith(prometheus.Labels{ - ifCounterNameLabel: item.InterfaceName, - ifCounterIndexLabel: fmt.Sprint(item.InterfaceIndex), - }) - if err != nil { - p.Log.Error(err) + // add gauges with corresponding labels into vectors + for k, vec := range p.ifCounterGaugeVecs { + stats.metrics[k], err = vec.GetMetricWith(prometheus.Labels{ + ifCounterNameLabel: item.InterfaceName, + ifCounterIndexLabel: fmt.Sprint(item.InterfaceIndex), + }) + if err != nil { + p.Log.Error(err) + } } } - } - stats.metrics[ifCounterRxPackets].Set(float64(item.RxPackets)) - stats.metrics[ifCounterRxBytes].Set(float64(item.RxBytes)) - stats.metrics[ifCounterRxErrors].Set(float64(item.RxErrors)) - stats.metrics[ifCounterTxPackets].Set(float64(item.TxPackets)) - stats.metrics[ifCounterTxBytes].Set(float64(item.TxBytes)) - stats.metrics[ifCounterTxErrors].Set(float64(item.TxErrors)) - stats.metrics[ifCounterDrops].Set(float64(item.Drops)) - stats.metrics[ifCounterPunts].Set(float64(item.Punts)) - stats.metrics[ifCounterIP4].Set(float64(item.IP4)) - stats.metrics[ifCounterIP6].Set(float64(item.IP6)) - stats.metrics[ifCounterRxNoBuf].Set(float64(item.RxNoBuf)) - stats.metrics[ifCounterRxMiss].Set(float64(item.RxMiss)) + stats.metrics[ifCounterRxPackets].Set(float64(item.RxPackets)) + stats.metrics[ifCounterRxBytes].Set(float64(item.RxBytes)) + stats.metrics[ifCounterRxErrors].Set(float64(item.RxErrors)) + stats.metrics[ifCounterTxPackets].Set(float64(item.TxPackets)) + stats.metrics[ifCounterTxBytes].Set(float64(item.TxBytes)) + stats.metrics[ifCounterTxErrors].Set(float64(item.TxErrors)) + stats.metrics[ifCounterDrops].Set(float64(item.Drops)) + stats.metrics[ifCounterPunts].Set(float64(item.Punts)) + stats.metrics[ifCounterIP4].Set(float64(item.IP4)) + stats.metrics[ifCounterIP6].Set(float64(item.IP6)) + stats.metrics[ifCounterRxNoBuf].Set(float64(item.RxNoBuf)) + stats.metrics[ifCounterRxMiss].Set(float64(item.RxMiss)) + } } } diff --git a/plugins/telemetry/telemetry.conf b/plugins/telemetry/telemetry.conf index d1f8027191..3a05580371 100644 --- a/plugins/telemetry/telemetry.conf +++ b/plugins/telemetry/telemetry.conf @@ -3,3 +3,7 @@ polling-interval: 30000000000 # If set to true, telemetry plugin is disabled. disabled: false + +# Skip collecting some of the metrics. +# runtime, memory, buffers, nodes, interfaces +#skipped: [nodes] diff --git a/plugins/telemetry/telemetry.go b/plugins/telemetry/telemetry.go index 1acfe4590f..9fb24a9d08 100644 --- a/plugins/telemetry/telemetry.go +++ b/plugins/telemetry/telemetry.go @@ -34,13 +34,6 @@ import ( _ "github.com/ligato/vpp-agent/plugins/telemetry/vppcalls/vpp1908" ) -const ( - // default period between updates - defaultUpdatePeriod = time.Second * 30 - // minimum period between updates - minimumUpdatePeriod = time.Second * 1 -) - var debug = os.Getenv("DEBUG_TELEMETRY") != "" // Plugin registers Telemetry Plugin @@ -54,6 +47,7 @@ type Plugin struct { // From config file updatePeriod time.Duration disabled bool + skipped map[string]bool wg sync.WaitGroup quit chan struct{} @@ -70,6 +64,7 @@ type Deps struct { // Init initializes Telemetry Plugin func (p *Plugin) Init() error { p.quit = make(chan struct{}) + p.skipped = make(map[string]bool, 0) // Telemetry config file config, err := p.loadConfig() @@ -92,6 +87,10 @@ func (p *Plugin) Init() error { p.Log.Warnf("polling period has to be at least %s, using default: %v", minimumUpdatePeriod, defaultUpdatePeriod) } + // Store map of skipped metrics + for _, skip := range config.Skipped { + p.skipped[skip] = true + } } // This serves as fallback if the config was not found or if the value is not set in config. if p.updatePeriod == 0 { From 6c6e0b87d3664daaa3f934f263e1a648f0eb4258 Mon Sep 17 00:00:00 2001 From: stanislav-chlebec <32060603+stanislav-chlebec@users.noreply.github.com> Date: Thu, 25 Jul 2019 14:13:51 +0200 Subject: [PATCH 07/10] Added CRUD integration tests for IPv4/IPv6 (#1419) * Added CRUD integration tests for IPv4/IPv6 routes in default VRF and VRF=2 Signed-off-by: Stanislav Chlebec * improving code Signed-off-by: Stanislav Chlebec * removed comments and parametrized value of VRF (vrfMetaIdx) * removed redundant initialisation to default value causes warnings in travis Signed-off-by: Stanislav Chlebec --- tests/integration/vpp/020_routes_test.go | 295 +++++++++++++++++++++++ 1 file changed, 295 insertions(+) diff --git a/tests/integration/vpp/020_routes_test.go b/tests/integration/vpp/020_routes_test.go index 85160657f5..7ade970bed 100644 --- a/tests/integration/vpp/020_routes_test.go +++ b/tests/integration/vpp/020_routes_test.go @@ -22,6 +22,7 @@ import ( vpp_l3 "github.com/ligato/vpp-agent/api/models/vpp/l3" "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/ifaceidx" + ifplugin_vppcalls "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/vppcalls" _ "github.com/ligato/vpp-agent/plugins/vpp/l3plugin" l3plugin_vppcalls "github.com/ligato/vpp-agent/plugins/vpp/l3plugin/vppcalls" "github.com/ligato/vpp-agent/plugins/vpp/l3plugin/vrfidx" @@ -63,3 +64,297 @@ func TestRoutes(t *testing.T) { t.Fatalf("expected dump to contain both IPv4 and IPv6 routes") } } + +func TestCRUDIPv4Route(t *testing.T) { + ctx := setupVPP(t) + defer ctx.teardownVPP() + + ih := ifplugin_vppcalls.CompatibleInterfaceVppHandler(ctx.vppBinapi, logrus.NewLogger("test")) + const ifName = "loop1" + ifIdx, err := ih.AddLoopbackInterface(ifName) + if err != nil { + t.Fatalf("creating interface failed: %v", err) + } + t.Logf("interface created %v", ifIdx) + + ifIndexes := ifaceidx.NewIfaceIndex(logrus.NewLogger("test-iface1"), "test-iface1") + ifIndexes.Put(ifName, &ifaceidx.IfaceMetadata{ + SwIfIndex: ifIdx, + }) + + var vrfMetaIdx uint32 + vrfIndexes := vrfidx.NewVRFIndex(logrus.NewLogger("test-vrf"), "test-vrf") + vrfIndexes.Put("vrf1-ipv4-vrf0", &vrfidx.VRFMetadata{Index: vrfMetaIdx, Protocol: vpp_l3.VrfTable_IPV4}) + + h := l3plugin_vppcalls.CompatibleL3VppHandler(ctx.vppBinapi, ifIndexes, vrfIndexes, logrus.NewLogger("test")) + + routes, errx := h.DumpRoutes() + if errx != nil { + t.Fatalf("dumping routes failed: %v", err) + } + routesCnt := len(routes) + t.Logf("%d routes dumped", routesCnt) + + newRoute := vpp_l3.Route{VrfId: 0, DstNetwork: "192.168.10.21/24", NextHopAddr: "192.168.30.1", OutgoingInterface: ifName} + err = h.VppAddRoute(&newRoute) + if err != nil { + t.Fatalf("adding route failed: %v", err) + } + t.Logf("route added: %+v", newRoute) + + routes, err = h.DumpRoutes() + routesCnt2 := len(routes) + if err != nil { + t.Fatalf("dumping routes failed: %v", err) + } + t.Logf("%d routes dumped", routesCnt2) + + if routesCnt+1 != routesCnt2 { + t.Errorf("Number of routes after adding of one route is not incremented by 1") + } + + newRouteIsPresent := false + for _, route := range routes { + if (route.Route.DstNetwork == newRoute.DstNetwork) && (route.Route.NextHopAddr == newRoute.NextHopAddr) && (route.Route.OutgoingInterface == newRoute.OutgoingInterface) { + newRouteIsPresent = true + break + } + } + if !newRouteIsPresent { + t.Error("Added route is not present in route dump") + } + + err = h.VppDelRoute(&newRoute) + if err != nil { + t.Fatalf("deleting route failed: %v", err) + } + t.Logf("route deleted") + + routes, err = h.DumpRoutes() + routesCnt3 := len(routes) + if err != nil { + t.Fatalf("dumping routes failed: %v", err) + } + t.Logf("%d routes dumped", routesCnt3) + if routesCnt2-1 != routesCnt3 { + t.Errorf("Number of routes after deleting of one route is not decremented by 1") + } + + for _, route := range routes { + if (route.Route.DstNetwork == newRoute.DstNetwork) && (route.Route.NextHopAddr == newRoute.NextHopAddr) && (route.Route.OutgoingInterface == newRoute.OutgoingInterface) { + t.Error("Added route is still present in route dump - should be deleted") + } + } + + vrfMetaIdx = 2 + err = h.AddVrfTable(&vpp_l3.VrfTable{Id: vrfMetaIdx, Protocol: vpp_l3.VrfTable_IPV4, Label: "table1"}) + if err != nil { + t.Fatalf("creating vrf table failed: %v", err) + } + t.Logf("vrf table 2 created") + vrfIndexes.Put("vrf1-ipv4-vrf2", &vrfidx.VRFMetadata{Index: vrfMetaIdx, Protocol: vpp_l3.VrfTable_IPV4}) + + routes, errx = h.DumpRoutes() + if errx != nil { + t.Fatalf("dumping routes failed: %v", err) + } + routesCnt = len(routes) + t.Logf("%d routes dumped", routesCnt) + + newRoute = vpp_l3.Route{VrfId: 2, DstNetwork: "192.168.10.21/24", NextHopAddr: "192.168.30.1", OutgoingInterface: ifName} + err = h.VppAddRoute(&newRoute) + if err != nil { + t.Fatalf("adding route failed: %v", err) + } + t.Logf("route added: %+v", newRoute) + + routes, err = h.DumpRoutes() + routesCnt2 = len(routes) + if err != nil { + t.Fatalf("dumping routes failed: %v", err) + } + t.Logf("%d routes dumped", routesCnt2) + + if routesCnt+1 != routesCnt2 { + t.Errorf("Number of routes after adding of one route is not incremented by 1") + } + + newRouteIsPresent = false + for _, route := range routes { + if (route.Route.DstNetwork == newRoute.DstNetwork) && (route.Route.NextHopAddr == newRoute.NextHopAddr) && (route.Route.OutgoingInterface == newRoute.OutgoingInterface) { + newRouteIsPresent = true + break + } + } + if !newRouteIsPresent { + t.Error("Added route is not present in route dump") + } + + err = h.VppDelRoute(&newRoute) + if err != nil { + t.Fatalf("deleting route failed: %v", err) + } + t.Logf("route deleted") + + routes, err = h.DumpRoutes() + routesCnt3 = len(routes) + if err != nil { + t.Fatalf("dumping routes failed: %v", err) + } + t.Logf("%d routes dumped", routesCnt3) + if routesCnt2-1 != routesCnt3 { + t.Errorf("Number of routes after deleting of one route is not decremented by 1") + } + + for _, route := range routes { + if (route.Route.DstNetwork == newRoute.DstNetwork) && (route.Route.NextHopAddr == newRoute.NextHopAddr) && (route.Route.OutgoingInterface == newRoute.OutgoingInterface) { + t.Error("Added route is still present in route dump - should be deleted") + } + } +} + +func TestCRUDIPv6Route(t *testing.T) { + ctx := setupVPP(t) + defer ctx.teardownVPP() + + ih := ifplugin_vppcalls.CompatibleInterfaceVppHandler(ctx.vppBinapi, logrus.NewLogger("test")) + const ifName = "loop1" + ifIdx, err := ih.AddLoopbackInterface(ifName) + if err != nil { + t.Fatalf("creating interface failed: %v", err) + } + t.Logf("interface created %v", ifIdx) + + ifIndexes := ifaceidx.NewIfaceIndex(logrus.NewLogger("test-iface1"), "test-iface1") + ifIndexes.Put(ifName, &ifaceidx.IfaceMetadata{ + SwIfIndex: ifIdx, + }) + + var vrfMetaIdx uint32 + vrfIndexes := vrfidx.NewVRFIndex(logrus.NewLogger("test-vrf"), "test-vrf") + vrfIndexes.Put("vrf1-ipv6-vrf0", &vrfidx.VRFMetadata{Index: vrfMetaIdx, Protocol: vpp_l3.VrfTable_IPV6}) + + h := l3plugin_vppcalls.CompatibleL3VppHandler(ctx.vppBinapi, ifIndexes, vrfIndexes, logrus.NewLogger("test")) + + routes, errx := h.DumpRoutes() + if errx != nil { + t.Fatalf("dumping routes failed: %v", err) + } + routesCnt := len(routes) + t.Logf("%d routes dumped", routesCnt) + + newRoute := vpp_l3.Route{VrfId: 0, DstNetwork: "fd30:0:0:1::/64", NextHopAddr: "fd31::1:1:0:0:1", OutgoingInterface: ifName} + err = h.VppAddRoute(&newRoute) + if err != nil { + t.Fatalf("adding route failed: %v", err) + } + t.Logf("route added: %+v", newRoute) + + routes, err = h.DumpRoutes() + routesCnt2 := len(routes) + if err != nil { + t.Fatalf("dumping routes failed: %v", err) + } + t.Logf("%d routes dumped", routesCnt2) + + if routesCnt+1 != routesCnt2 { + t.Errorf("Number of routes after adding of one route is not incremented by 1") + } + + newRouteIsPresent := false + for _, route := range routes { + if (route.Route.DstNetwork == newRoute.DstNetwork) && (route.Route.NextHopAddr == newRoute.NextHopAddr) && (route.Route.OutgoingInterface == newRoute.OutgoingInterface) { + newRouteIsPresent = true + } + } + if !newRouteIsPresent { + t.Error("Added route is not present in route dump") + } + + err = h.VppDelRoute(&newRoute) + if err != nil { + t.Fatalf("deleting route failed: %v", err) + } + t.Logf("route deleted") + + routes, err = h.DumpRoutes() + routesCnt3 := len(routes) + if err != nil { + t.Fatalf("dumping routes failed: %v", err) + } + t.Logf("%d routes dumped", routesCnt3) + if routesCnt2-1 != routesCnt3 { + t.Errorf("Number of routes after deleting of one route is not decremented by 1") + } + + for _, route := range routes { + if (route.Route.DstNetwork == newRoute.DstNetwork) && (route.Route.NextHopAddr == newRoute.NextHopAddr) && (route.Route.OutgoingInterface == newRoute.OutgoingInterface) { + t.Error("Added route is still present in route dump - should be deleted") + } + } + + vrfMetaIdx = 2 + err = h.AddVrfTable(&vpp_l3.VrfTable{Id: vrfMetaIdx, Protocol: vpp_l3.VrfTable_IPV6, Label: "table1"}) + if err != nil { + t.Fatalf("creating vrf table failed: %v", err) + } + t.Logf("vrf table 2 created") + vrfIndexes.Put("vrf1-ipv6-vrf2", &vrfidx.VRFMetadata{Index: vrfMetaIdx, Protocol: vpp_l3.VrfTable_IPV6}) + + routes, errx = h.DumpRoutes() + if errx != nil { + t.Fatalf("dumping routes failed: %v", err) + } + routesCnt = len(routes) + t.Logf("%d routes dumped", routesCnt) + + newRoute = vpp_l3.Route{VrfId: 2, DstNetwork: "fd30:0:0:1::/64", NextHopAddr: "fd31::1:1:0:0:1", OutgoingInterface: ifName} + err = h.VppAddRoute(&newRoute) + if err != nil { + t.Fatalf("adding route failed: %v", err) + } + t.Logf("route added: %+v", newRoute) + + routes, err = h.DumpRoutes() + routesCnt2 = len(routes) + if err != nil { + t.Fatalf("dumping routes failed: %v", err) + } + t.Logf("%d routes dumped", routesCnt2) + + if routesCnt+1 != routesCnt2 { + t.Errorf("Number of routes after adding of one route is not incremented by 1") + } + + newRouteIsPresent = false + for _, route := range routes { + if (route.Route.DstNetwork == newRoute.DstNetwork) && (route.Route.NextHopAddr == newRoute.NextHopAddr) && (route.Route.OutgoingInterface == newRoute.OutgoingInterface) { + newRouteIsPresent = true + } + } + if !newRouteIsPresent { + t.Error("Added route is not present in route dump") + } + + err = h.VppDelRoute(&newRoute) + if err != nil { + t.Fatalf("deleting route failed: %v", err) + } + t.Logf("route deleted") + + routes, err = h.DumpRoutes() + routesCnt3 = len(routes) + if err != nil { + t.Fatalf("dumping routes failed: %v", err) + } + t.Logf("%d routes dumped", routesCnt3) + if routesCnt2-1 != routesCnt3 { + t.Errorf("Number of routes after deleting of one route is not decremented by 1") + } + + for _, route := range routes { + if (route.Route.DstNetwork == newRoute.DstNetwork) && (route.Route.NextHopAddr == newRoute.NextHopAddr) && (route.Route.OutgoingInterface == newRoute.OutgoingInterface) { + t.Error("Added route is still present in route dump - should be deleted") + } + } +} From e1681355ba01ed1fd59b55300f46d4dacca2a833 Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Fri, 26 Jul 2019 09:21:26 +0200 Subject: [PATCH 08/10] Minor enhancements and code cleanups (#1420) * Minor enhancement for transaction summary log Signed-off-by: Ondrej Fabry * Add make target for remote debugging with delve Signed-off-by: Ondrej Fabry * Minor code cleanup in vpp ifplugin Signed-off-by: Ondrej Fabry * Fix error check when renaming tap and cleanup code Signed-off-by: Ondrej Fabry --- Makefile | 3 + plugins/kvscheduler/api/txn_options.go | 2 +- plugins/kvscheduler/api/txn_record.go | 6 +- plugins/kvscheduler/plugin_scheduler.go | 2 +- plugins/kvscheduler/refresh.go | 2 +- plugins/kvscheduler/txn_process.go | 8 +-- plugins/kvscheduler/txn_record.go | 24 +++---- .../linux/ifplugin/descriptor/interface.go | 71 +++++++++++-------- .../ifplugin/descriptor/interface_tap.go | 19 ++--- .../ifplugin/descriptor/interface_veth.go | 13 ++-- plugins/vpp/ifplugin/descriptor/interface.go | 8 +-- plugins/vpp/ifplugin/descriptor/rx_mode.go | 20 +++--- .../vpp/ifplugin/descriptor/rx_placement.go | 11 ++- 13 files changed, 102 insertions(+), 87 deletions(-) diff --git a/Makefile b/Makefile index 9f670f23fd..97c671a4e7 100644 --- a/Makefile +++ b/Makefile @@ -95,6 +95,9 @@ clean-examples: cd examples/localclient_vpp/nat && go clean cd examples/localclient_vpp/plugins && go clean +debug-remote: + cd ./cmd/vpp-agent && dlv debug --headless --listen=:2345 --api-version=2 --accept-multiclient + # ------------------------------- # Testing # ------------------------------- diff --git a/plugins/kvscheduler/api/txn_options.go b/plugins/kvscheduler/api/txn_options.go index e515824d96..3111ac2a68 100644 --- a/plugins/kvscheduler/api/txn_options.go +++ b/plugins/kvscheduler/api/txn_options.go @@ -268,4 +268,4 @@ func WithSimulation(ctx context.Context) context.Context { func IsWithSimulation(ctx context.Context) bool { _, withSimulation := ctx.Value(txnSimulationCtxKey).(*txnSimulationOpt) return withSimulation -} \ No newline at end of file +} diff --git a/plugins/kvscheduler/api/txn_record.go b/plugins/kvscheduler/api/txn_record.go index 8153ecd736..e333e6b4fa 100644 --- a/plugins/kvscheduler/api/txn_record.go +++ b/plugins/kvscheduler/api/txn_record.go @@ -49,9 +49,9 @@ func (t TxnType) String() string { case NBTransaction: return "NB Transaction" case RetryFailedOps: - return "RETRY" + return "Retry Transaction" } - return "UNKNOWN" + return "UndefinedTxnType" } // RecordedTxn is used to record executed transaction. @@ -128,7 +128,7 @@ func (txn *RecordedTxn) StringWithOpts(resultOnly, verbose bool, indent int) str if !resultOnly { // transaction arguments str += indent1 + "* transaction arguments:\n" - str += indent2 + fmt.Sprintf("- seq-num: %d\n", txn.SeqNum) + str += indent2 + fmt.Sprintf("- seqNum: %d\n", txn.SeqNum) if txn.TxnType == NBTransaction && txn.ResyncType != NotResync { ResyncType := "Full Resync" if txn.ResyncType == DownstreamResync { diff --git a/plugins/kvscheduler/plugin_scheduler.go b/plugins/kvscheduler/plugin_scheduler.go index c5e9bcaaa2..e951bfdb90 100644 --- a/plugins/kvscheduler/plugin_scheduler.go +++ b/plugins/kvscheduler/plugin_scheduler.go @@ -288,7 +288,7 @@ func (s *Scheduler) TransactionBarrier() { // PushSBNotification notifies about a spontaneous value change(s) in the SB // plane (i.e. not triggered by NB transaction). -func (s *Scheduler) PushSBNotification(notif... kvs.KVWithMetadata) error { +func (s *Scheduler) PushSBNotification(notif ...kvs.KVWithMetadata) error { txn := &transaction{ txnType: kvs.SBNotification, } diff --git a/plugins/kvscheduler/refresh.go b/plugins/kvscheduler/refresh.go index 5cd644dcfe..2f14091ed3 100644 --- a/plugins/kvscheduler/refresh.go +++ b/plugins/kvscheduler/refresh.go @@ -571,4 +571,4 @@ func (s *Scheduler) validRetrievedDerivedKV(node graph.Node, descriptor *kvs.KVD // return true -> let's overwrite invalidly retrieved derived value } return true -} \ No newline at end of file +} diff --git a/plugins/kvscheduler/txn_process.go b/plugins/kvscheduler/txn_process.go index fae5ff1ec9..6ad934f2e9 100644 --- a/plugins/kvscheduler/txn_process.go +++ b/plugins/kvscheduler/txn_process.go @@ -207,7 +207,7 @@ func (s *Scheduler) preProcessNBTransaction(txn *transaction) (skip bool) { } // for resync refresh the graph + collect deletes - graphW := s.graph.Write(true,false) + graphW := s.graph.Write(true, false) defer graphW.Release() s.resyncCount++ @@ -344,7 +344,7 @@ func (s *Scheduler) postProcessTransaction(txn *transaction, executed kvs.Record if toRefresh.Length() > 0 { // changes brought by refresh triggered solely for the verification are // not saved into the graph - graphW := s.graph.Write(afterErrRefresh,false) + graphW := s.graph.Write(afterErrRefresh, false) s.refreshGraph(graphW, toRefresh, nil, afterErrRefresh) s.scheduleRetries(txn, graphW, toRetry) @@ -420,7 +420,7 @@ func (s *Scheduler) postProcessTransaction(txn *transaction, executed kvs.Record // delete removed values from the graph after the notifications have been sent if removed.Length() > 0 { - graphW := s.graph.Write(true,true) + graphW := s.graph.Write(true, true) for _, key := range removed.Iterate() { graphW.DeleteNode(key) } @@ -429,7 +429,7 @@ func (s *Scheduler) postProcessTransaction(txn *transaction, executed kvs.Record } // scheduleRetries schedules a series of re-try transactions for failed values -func (s *Scheduler) scheduleRetries(txn *transaction, graphR graph.ReadAccess, toRetry utils.KeySet,) { +func (s *Scheduler) scheduleRetries(txn *transaction, graphR graph.ReadAccess, toRetry utils.KeySet) { // split values based on the retry metadata retryTxns := make(map[retryTxnMeta]*retryTxn) for _, retryKey := range toRetry.Iterate() { diff --git a/plugins/kvscheduler/txn_record.go b/plugins/kvscheduler/txn_record.go index e7e2e81745..04045714fc 100644 --- a/plugins/kvscheduler/txn_record.go +++ b/plugins/kvscheduler/txn_record.go @@ -137,21 +137,16 @@ func (s *Scheduler) preRecordTransaction(txn *transaction, planned kvs.RecordedT // if enabled, print txn summary if s.config.PrintTxnSummary { // build header for the log - txnInfo := txn.txnType.String() + txnInfo := "" if txn.txnType == kvs.NBTransaction && txn.nb.resyncType != kvs.NotResync { - resyncType := "Full Resync" - if txn.nb.resyncType == kvs.DownstreamResync { - resyncType = "SB Sync" - } - if txn.nb.resyncType == kvs.UpstreamResync { - resyncType = "NB Sync" - } - txnInfo = fmt.Sprintf("%s (%s)", txn.txnType.String(), resyncType) + txnInfo = fmt.Sprintf("%s", txn.nb.resyncType.String()) + } else if txn.txnType == kvs.RetryFailedOps && txn.retry != nil { + txnInfo = fmt.Sprintf("retrying TX #%d (attempt %d)", txn.retry.txnSeqNum, txn.retry.attempt) } + msg := fmt.Sprintf("#%d - %s", record.SeqNum, txn.txnType.String()) + n := 115 - len(msg) var buf strings.Builder buf.WriteString("+======================================================================================================================+\n") - msg := fmt.Sprintf("Transaction #%d", record.SeqNum) - n := 115 - len(msg) buf.WriteString(fmt.Sprintf("| %s %"+strconv.Itoa(n)+"s |\n", msg, txnInfo)) buf.WriteString("+======================================================================================================================+\n") buf.WriteString(record.StringWithOpts(false, false, 2)) @@ -172,12 +167,15 @@ func (s *Scheduler) recordTransaction(txn *transaction, txnRecord *kvs.RecordedT txnRecord.Executed = executed if s.config.PrintTxnSummary { + txnType := txn.txnType.String() + msg := fmt.Sprintf("#%d - %s", txnRecord.SeqNum, txnType) + elapsed := stop.Sub(start) + msg2 := fmt.Sprintf("took %v", elapsed.Round(time.Microsecond*100)) + var buf strings.Builder buf.WriteString("o----------------------------------------------------------------------------------------------------------------------o\n") buf.WriteString(txnRecord.StringWithOpts(true, false, 2)) buf.WriteString("x----------------------------------------------------------------------------------------------------------------------x\n") - msg := fmt.Sprintf("#%d", txnRecord.SeqNum) - msg2 := fmt.Sprintf("took %v", stop.Sub(start).Round(time.Microsecond*100)) buf.WriteString(fmt.Sprintf("| %s %"+fmt.Sprint(115-len(msg))+"s |\n", msg, msg2)) buf.WriteString("x----------------------------------------------------------------------------------------------------------------------x\n") fmt.Println(buf.String()) diff --git a/plugins/linux/ifplugin/descriptor/interface.go b/plugins/linux/ifplugin/descriptor/interface.go index 08355df10d..65aff7805d 100644 --- a/plugins/linux/ifplugin/descriptor/interface.go +++ b/plugins/linux/ifplugin/descriptor/interface.go @@ -27,7 +27,6 @@ import ( "github.com/gogo/protobuf/proto" prototypes "github.com/gogo/protobuf/types" "github.com/pkg/errors" - "github.com/vishvananda/netlink" "golang.org/x/sys/unix" "github.com/ligato/cn-infra/idxmap" @@ -249,28 +248,42 @@ func (d *InterfaceDescriptor) MetadataFactory() idxmap.NamedMappingRW { // Validate validates Linux interface configuration. func (d *InterfaceDescriptor) Validate(key string, linuxIf *interfaces.Interface) error { + // validate name (this should never happen, since key is derived from name) if linuxIf.GetName() == "" { return kvs.NewInvalidValueError(ErrInterfaceWithoutName, "name") } - addrs := linuxIf.GetIpAddresses() - for _, a := range addrs { + + // validate IP addresses + for _, a := range linuxIf.GetIpAddresses() { + // TODO: perhaps we could assume default mask if there isnt one? if _, _, err := net.ParseCIDR(a); err != nil { return kvs.NewInvalidValueError(ErrInvalidIPWithMask, "ip_addresses") } } - if linuxIf.GetType() == interfaces.Interface_UNDEFINED { - return kvs.NewInvalidValueError(ErrInterfaceWithoutType, "type") - } - if linuxIf.GetType() == interfaces.Interface_TAP_TO_VPP && d.vppIfPlugin == nil { - return ErrTAPRequiresVPPIfPlugin + // validate namespace + if ns := linuxIf.GetNamespace(); ns != nil { + if ns.GetType() == namespace.NetNamespace_UNDEFINED || ns.GetReference() == "" { + return kvs.NewInvalidValueError(ErrNamespaceWithoutReference, "namespace") + } } - if linuxIf.GetNamespace() != nil && - (linuxIf.GetNamespace().GetType() == namespace.NetNamespace_UNDEFINED || - linuxIf.GetNamespace().GetReference() == "") { - return kvs.NewInvalidValueError(ErrNamespaceWithoutReference, "namespace") + + // validate type + switch linuxIf.GetType() { + case interfaces.Interface_LOOPBACK: + if linuxIf.GetLink() != nil { + return kvs.NewInvalidValueError(ErrInterfaceReferenceMismatch, "link") + } + case interfaces.Interface_TAP_TO_VPP: + if d.vppIfPlugin == nil { + return ErrTAPRequiresVPPIfPlugin + } + case interfaces.Interface_UNDEFINED: + return kvs.NewInvalidValueError(ErrInterfaceWithoutType, "type") } - switch linuxIf.Link.(type) { + + // validate link + switch linuxIf.GetLink().(type) { case *interfaces.Interface_Tap: if linuxIf.GetType() != interfaces.Interface_TAP_TO_VPP { return kvs.NewInvalidValueError(ErrInterfaceReferenceMismatch, "link") @@ -723,6 +736,7 @@ func (d *InterfaceDescriptor) Retrieve(correlate []adapter.InterfaceKVWithMetada // receive results from the go routines ifaces := make(map[string]adapter.InterfaceKVWithMetadata) // interface logical name -> interface data indexes := make(map[int]struct{}) // already retrieved interfaces by their Linux indexes + for idx := 0; idx < goRoutinesCnt; idx++ { retrieved := <-ch if retrieved.err != nil { @@ -732,7 +746,7 @@ func (d *InterfaceDescriptor) Retrieve(correlate []adapter.InterfaceKVWithMetada // skip if this interface was already retrieved and this is not the expected // namespace from correlation - remember, the same namespace may have // multiple different references - rewrite := false + var rewrite bool if _, alreadyRetrieved := indexes[kv.Metadata.LinuxIfIndex]; alreadyRetrieved { if expCfg, hasExpCfg := ifCfg[kv.Value.Name]; hasExpCfg { if proto.Equal(expCfg.Namespace, kv.Value.Namespace) { @@ -857,19 +871,23 @@ func (d *InterfaceDescriptor) retrieveInterfaces(nsList []*namespace.NetNamespac alias = strings.TrimPrefix(alias, agentPrefix) // parse alias to obtain logical references - var vppTapIfName string - if link.Type() == (&netlink.Veth{}).Type() { - var vethPeerIfName string + if link.Type() == "veth" { iface.Type = interfaces.Interface_VETH + var vethPeerIfName string iface.Name, vethPeerIfName = parseVethAlias(alias) iface.Link = &interfaces.Interface_Veth{ - Veth: &interfaces.VethLink{PeerIfName: vethPeerIfName}, + Veth: &interfaces.VethLink{ + PeerIfName: vethPeerIfName, + }, } - } else if link.Type() == (&netlink.Tuntap{}).Type() || link.Type() == "tun" /* not defined in vishvananda */ { + } else if link.Type() == "tuntap" || link.Type() == "tun" /* not defined in vishvananda */ { iface.Type = interfaces.Interface_TAP_TO_VPP + var vppTapIfName string iface.Name, vppTapIfName, _ = parseTapAlias(alias) iface.Link = &interfaces.Interface_Tap{ - Tap: &interfaces.TapLink{VppTapIfName: vppTapIfName}, + Tap: &interfaces.TapLink{ + VppTapIfName: vppTapIfName, + }, } } else if link.Attrs().Name == defaultLoopbackName { iface.Type = interfaces.Interface_LOOPBACK @@ -878,9 +896,8 @@ func (d *InterfaceDescriptor) retrieveInterfaces(nsList []*namespace.NetNamespac // unsupported interface type supposedly configured by agent => print warning d.log.WithFields(logging.Fields{ "if-host-name": link.Attrs().Name, - "if-type": link.Type(), "namespace": nsRef, - }).Warn("Managed interface of unsupported type") + }).Warnf("Managed interface of unsupported type: %s", link.Type()) continue } @@ -941,7 +958,7 @@ func (d *InterfaceDescriptor) retrieveInterfaces(nsList []*namespace.NetNamespac Origin: kvs.FromNB, Metadata: &ifaceidx.LinuxIfMetadata{ LinuxIfIndex: link.Attrs().Index, - VPPTapName: vppTapIfName, + VPPTapName: iface.GetTap().GetVppTapIfName(), Namespace: nsRef, }, }) @@ -983,8 +1000,7 @@ func (d *InterfaceDescriptor) setInterfaceNamespace(ctx nslinuxcalls.NamespaceMg } // Move the interface into the namespace. - err = d.ifHandler.SetLinkNamespace(link, ns) - if err != nil { + if err := d.ifHandler.SetLinkNamespace(link, ns); err != nil { return errors.Errorf("failed to set interface %s file descriptor: %v", link.Attrs().Name, err) } @@ -1009,8 +1025,7 @@ func (d *InterfaceDescriptor) setInterfaceNamespace(ctx nslinuxcalls.NamespaceMg if !isIPv6 && address.IP.IsLinkLocalUnicast() { continue } - err = d.ifHandler.AddInterfaceIP(ifName, address) - if err != nil { + if err := d.ifHandler.AddInterfaceIP(ifName, address); err != nil { if err.Error() == "file exists" { continue } @@ -1098,7 +1113,6 @@ func getSysctl(name string) (string, error) { if err != nil { return "", err } - return string(data[:len(data)-1]), nil } @@ -1108,6 +1122,5 @@ func setSysctl(name, value string) (string, error) { if err := ioutil.WriteFile(fullName, []byte(value), 0644); err != nil { return "", err } - return getSysctl(name) } diff --git a/plugins/linux/ifplugin/descriptor/interface_tap.go b/plugins/linux/ifplugin/descriptor/interface_tap.go index f6833b49c4..aa2dc87dfe 100644 --- a/plugins/linux/ifplugin/descriptor/interface_tap.go +++ b/plugins/linux/ifplugin/descriptor/interface_tap.go @@ -27,8 +27,10 @@ import ( // createTAPToVPP moves Linux-side of the VPP-TAP interface to the destination namespace // and sets the requested host name, IP addresses, etc. -func (d *InterfaceDescriptor) createTAPToVPP(nsCtx nslinuxcalls.NamespaceMgmtCtx, key string, - linuxIf *interfaces.Interface) (metadata *ifaceidx.LinuxIfMetadata, err error) { +func (d *InterfaceDescriptor) createTAPToVPP( + nsCtx nslinuxcalls.NamespaceMgmtCtx, key string, linuxIf *interfaces.Interface, +) ( + md *ifaceidx.LinuxIfMetadata, err error) { // determine TAP interface name as set by VPP ifplugin vppTapName := linuxIf.GetTap().GetVppTapIfName() @@ -45,7 +47,8 @@ func (d *InterfaceDescriptor) createTAPToVPP(nsCtx nslinuxcalls.NamespaceMgmtCtx agentPrefix := d.serviceLabel.GetAgentPrefix() // add alias to associate TAP with the logical name and VPP-TAP reference - err = d.ifHandler.SetInterfaceAlias(vppTapHostName, agentPrefix+getTapAlias(linuxIf, vppTapHostName)) + alias := agentPrefix + getTapAlias(linuxIf, vppTapHostName) + err = d.ifHandler.SetInterfaceAlias(vppTapHostName, alias) if err != nil { d.log.Error(err) return nil, err @@ -67,8 +70,7 @@ func (d *InterfaceDescriptor) createTAPToVPP(nsCtx nslinuxcalls.NamespaceMgmtCtx defer revert() // rename from temporary host name to the request host name - d.ifHandler.RenameInterface(vppTapHostName, hostName) - if err != nil { + if err := d.ifHandler.RenameInterface(vppTapHostName, hostName); err != nil { d.log.Error(err) return nil, err } @@ -79,13 +81,12 @@ func (d *InterfaceDescriptor) createTAPToVPP(nsCtx nslinuxcalls.NamespaceMgmtCtx d.log.Error(err) return nil, err } - metadata = &ifaceidx.LinuxIfMetadata{ + + return &ifaceidx.LinuxIfMetadata{ VPPTapName: vppTapName, Namespace: linuxIf.Namespace, LinuxIfIndex: link.Attrs().Index, - } - - return metadata, nil + }, nil } // deleteAutoTAP returns TAP interface back to the default namespace and renames diff --git a/plugins/linux/ifplugin/descriptor/interface_veth.go b/plugins/linux/ifplugin/descriptor/interface_veth.go index 630c9f3521..fc9a94140f 100644 --- a/plugins/linux/ifplugin/descriptor/interface_veth.go +++ b/plugins/linux/ifplugin/descriptor/interface_veth.go @@ -26,8 +26,10 @@ import ( // createVETH creates a new VETH pair if neither of VETH-ends are configured, or just // applies configuration to the unfinished VETH-end with a temporary host name. -func (d *InterfaceDescriptor) createVETH(nsCtx nslinuxcalls.NamespaceMgmtCtx, key string, - linuxIf *interfaces.Interface) (metadata *ifaceidx.LinuxIfMetadata, err error) { +func (d *InterfaceDescriptor) createVETH( + nsCtx nslinuxcalls.NamespaceMgmtCtx, key string, linuxIf *interfaces.Interface, +) ( + md *ifaceidx.LinuxIfMetadata, err error) { // determine host/logical/temporary interface names hostName := getHostIfName(linuxIf) @@ -92,12 +94,11 @@ func (d *InterfaceDescriptor) createVETH(nsCtx nslinuxcalls.NamespaceMgmtCtx, ke d.log.Error(err) return nil, err } - metadata = &ifaceidx.LinuxIfMetadata{ + + return &ifaceidx.LinuxIfMetadata{ Namespace: linuxIf.Namespace, LinuxIfIndex: link.Attrs().Index, - } - - return metadata, nil + }, nil } // deleteVETH either un-configures one VETH-end if the other end is still configured, or diff --git a/plugins/vpp/ifplugin/descriptor/interface.go b/plugins/vpp/ifplugin/descriptor/interface.go index 6fc00d59d0..f9c92a2edc 100644 --- a/plugins/vpp/ifplugin/descriptor/interface.go +++ b/plugins/vpp/ifplugin/descriptor/interface.go @@ -360,13 +360,13 @@ func (d *InterfaceDescriptor) Validate(key string, intf *interfaces.Interface) e } // validate interface type defined - if intf.Type == interfaces.Interface_UNDEFINED_TYPE { + if intf.GetType() == interfaces.Interface_UNDEFINED_TYPE { return kvs.NewInvalidValueError(ErrInterfaceWithoutType, "type") } // validate link with interface type linkMismatchErr := kvs.NewInvalidValueError(ErrInterfaceLinkMismatch, "link") - switch intf.Link.(type) { + switch intf.GetLink().(type) { case *interfaces.Interface_Sub: if intf.Type != interfaces.Interface_SUB_INTERFACE { return linkMismatchErr @@ -433,7 +433,7 @@ func (d *InterfaceDescriptor) Validate(key string, intf *interfaces.Interface) e } } - // validate Rx Placement before it gets derived out + // validate rx placements before before deriving for i, rxPlacement1 := range intf.GetRxPlacements() { for j := i + 1; j < len(intf.GetRxPlacements()); j++ { rxPlacement2 := intf.GetRxPlacements()[j] @@ -607,7 +607,7 @@ func (d *InterfaceDescriptor) DerivedValues(key string, intf *interfaces.Interfa // Rx mode if len(intf.GetRxModes()) > 0 { derValues = append(derValues, kvs.KeyValuePair{ - Key: interfaces.RxModesKey(intf.GetName()), + Key: interfaces.RxModesKey(intf.GetName()), Value: &interfaces.Interface{ Name: intf.GetName(), Type: intf.GetType(), diff --git a/plugins/vpp/ifplugin/descriptor/rx_mode.go b/plugins/vpp/ifplugin/descriptor/rx_mode.go index 59130aafc5..3a9a6ccd68 100644 --- a/plugins/vpp/ifplugin/descriptor/rx_mode.go +++ b/plugins/vpp/ifplugin/descriptor/rx_mode.go @@ -68,16 +68,16 @@ func NewRxModeDescriptor(ifHandler vppcalls.InterfaceVppAPI, ifIndex ifaceidx.If } typedDescr := &adapter.RxModeDescriptor{ - Name: RxModeDescriptorName, - KeySelector: ctx.IsInterfaceRxModeKey, + Name: RxModeDescriptorName, + KeySelector: ctx.IsInterfaceRxModeKey, // proto message Interface is only used as container for RxMode - ValueTypeName: proto.MessageName(&interfaces.Interface{}), + ValueTypeName: proto.MessageName(&interfaces.Interface{}), ValueComparator: ctx.EquivalentRxMode, - Validate: ctx.Validate, - Create: ctx.Create, - Update: ctx.Update, - Delete: ctx.Delete, - Dependencies: ctx.Dependencies, + Validate: ctx.Validate, + Create: ctx.Create, + Update: ctx.Update, + Delete: ctx.Delete, + Dependencies: ctx.Dependencies, } return adapter.NewRxModeDescriptor(typedDescr) @@ -131,7 +131,7 @@ func (d *RxModeDescriptor) Validate(key string, ifaceWithRxMode *interfaces.Inte for i, rxMode1 := range ifaceWithRxMode.GetRxModes() { if rxMode1.Mode == interfaces.Interface_RxMode_UNKNOWN { if rxMode1.DefaultMode { - return kvs.NewInvalidValueError(ErrUndefinedRxMode,"rx_mode[default]") + return kvs.NewInvalidValueError(ErrUndefinedRxMode, "rx_mode[default]") } return kvs.NewInvalidValueError(ErrUndefinedRxMode, fmt.Sprintf("rx_mode[.queue=%d]", rxMode1.Queue)) @@ -142,7 +142,7 @@ func (d *RxModeDescriptor) Validate(key string, ifaceWithRxMode *interfaces.Inte continue } if rxMode1.DefaultMode { - return kvs.NewInvalidValueError(ErrRedefinedRxMode,"rx_mode[default]") + return kvs.NewInvalidValueError(ErrRedefinedRxMode, "rx_mode[default]") } if rxMode1.Queue == rxMode2.Queue { return kvs.NewInvalidValueError(ErrRedefinedRxMode, diff --git a/plugins/vpp/ifplugin/descriptor/rx_placement.go b/plugins/vpp/ifplugin/descriptor/rx_placement.go index 393e3b51ac..e51e416bd5 100644 --- a/plugins/vpp/ifplugin/descriptor/rx_placement.go +++ b/plugins/vpp/ifplugin/descriptor/rx_placement.go @@ -15,9 +15,9 @@ package descriptor import ( - "github.com/pkg/errors" "github.com/gogo/protobuf/proto" "github.com/ligato/cn-infra/logging" + "github.com/pkg/errors" interfaces "github.com/ligato/vpp-agent/api/models/vpp/interfaces" kvs "github.com/ligato/vpp-agent/plugins/kvscheduler/api" @@ -70,8 +70,7 @@ func (d *RxPlacementDescriptor) IsInterfaceRxPlacementKey(key string) bool { } // EquivalentRxMode compares Rx placements for equivalency. -func (d *RxPlacementDescriptor) EquivalentRxPlacement(key string, - oldRxPl, newRxPl *interfaces.Interface_RxPlacement) bool { +func (d *RxPlacementDescriptor) EquivalentRxPlacement(key string, oldRxPl, newRxPl *interfaces.Interface_RxPlacement) bool { if (oldRxPl.MainThread != newRxPl.MainThread) || (!oldRxPl.MainThread && oldRxPl.Worker != newRxPl.Worker) { @@ -83,7 +82,7 @@ func (d *RxPlacementDescriptor) EquivalentRxPlacement(key string, // Create configures RxPlacement for a given interface queue. // Please note the proto message Interface is only used as container for RxMode. // Only interface name, type and Rx mode are set. -func (d *RxPlacementDescriptor) Create(key string, rxPlacement *interfaces.Interface_RxPlacement) (metadata interface{}, err error) { +func (d *RxPlacementDescriptor) Create(key string, rxPlacement *interfaces.Interface_RxPlacement) (md interface{}, err error) { ifaceName, _, _ := interfaces.ParseRxPlacementKey(key) ifMeta, found := d.ifIndex.LookupByName(ifaceName) if !found { @@ -108,7 +107,7 @@ func (d *RxPlacementDescriptor) Delete(key string, rxPlacement *interfaces.Inter // Dependencies informs scheduler that Rx placement configuration cannot be applied // until the interface link is UP. -func (d *RxPlacementDescriptor) Dependencies(key string, rxPlacement *interfaces.Interface_RxPlacement) (deps []kvs.Dependency) { +func (d *RxPlacementDescriptor) Dependencies(key string, rxPlacement *interfaces.Interface_RxPlacement) []kvs.Dependency { ifaceName, _, _ := interfaces.ParseRxPlacementKey(key) return []kvs.Dependency{ { @@ -116,4 +115,4 @@ func (d *RxPlacementDescriptor) Dependencies(key string, rxPlacement *interfaces Key: interfaces.LinkStateKey(ifaceName, true), }, } -} \ No newline at end of file +} From 94a842eb62dadb98bff739ece49a1e5983254c33 Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Fri, 26 Jul 2019 10:58:44 +0200 Subject: [PATCH 09/10] Add integration test for IP address (#1421) Signed-off-by: Ondrej Fabry --- tests/integration/vpp/010_interfaces_test.go | 29 ++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/integration/vpp/010_interfaces_test.go b/tests/integration/vpp/010_interfaces_test.go index dd809600bc..6c0956262a 100644 --- a/tests/integration/vpp/010_interfaces_test.go +++ b/tests/integration/vpp/010_interfaces_test.go @@ -15,6 +15,7 @@ package vpp import ( + "net" "testing" "github.com/ligato/cn-infra/logging/logrus" @@ -24,6 +25,34 @@ import ( ifplugin_vppcalls "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/vppcalls" ) +func TestInterfaceIP(t *testing.T) { + ctx := setupVPP(t) + defer ctx.teardownVPP() + + h := ifplugin_vppcalls.CompatibleInterfaceVppHandler(ctx.vppBinapi, logrus.NewLogger("test")) + + tests := []struct { + name string + ipnet net.IPNet + }{ + {"basic ipv4", net.IPNet{IP: net.IPv4(10, 0, 0, 1), Mask: net.IPMask{255, 255, 255, 0}}}, + {"basic ipv6", net.IPNet{IP: net.ParseIP("::1"), Mask: net.IPMask{255, 255, 255, 0}}}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ifIdx, err := h.AddLoopbackInterface("loop0") + if err != nil { + t.Fatalf("creating loopback interface failed: %v", err) + } + t.Logf("loop0 index: %+v", ifIdx) + + if err := h.AddInterfaceIP(ifIdx, &test.ipnet); err != nil { + t.Fatalf("adding interface IP failed: %v", err) + } + }) + } +} + func TestInterfaceDumpState(t *testing.T) { ctx := setupVPP(t) defer ctx.teardownVPP() From 75214a02a1c8aa5af7385c1f01331e128adc0128 Mon Sep 17 00:00:00 2001 From: stanislav-chlebec <32060603+stanislav-chlebec@users.noreply.github.com> Date: Fri, 26 Jul 2019 16:25:06 +0200 Subject: [PATCH 10/10] added arp crud integration test (#1422) * added arp crud integration test Signed-off-by: Stanislav Chlebec * comments removed * added more asserts - asserts related to number of arp entries in arp dump - asserting of fields of arp entry - assert non presence in arp dump - hard-coded index replaced by generated one stored in the variable ifIdx Signed-off-by: Stanislav Chlebec * simplify assert (omitting assert of Static field) Signed-off-by: Stanislav Chlebec --- tests/integration/vpp/030_arp_test.go | 138 ++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 tests/integration/vpp/030_arp_test.go diff --git a/tests/integration/vpp/030_arp_test.go b/tests/integration/vpp/030_arp_test.go new file mode 100644 index 0000000000..c6d0d0a8d2 --- /dev/null +++ b/tests/integration/vpp/030_arp_test.go @@ -0,0 +1,138 @@ +// Copyright (c) 2019 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package vpp + +import ( + "github.com/ligato/cn-infra/logging/logrus" + "strings" + "testing" + + vpp_l3 "github.com/ligato/vpp-agent/api/models/vpp/l3" + "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/ifaceidx" + ifplugin_vppcalls "github.com/ligato/vpp-agent/plugins/vpp/ifplugin/vppcalls" + _ "github.com/ligato/vpp-agent/plugins/vpp/l3plugin" + l3plugin_vppcalls "github.com/ligato/vpp-agent/plugins/vpp/l3plugin/vppcalls" + "github.com/ligato/vpp-agent/plugins/vpp/l3plugin/vrfidx" +) + +func TestArp(t *testing.T) { + ctx := setupVPP(t) + defer ctx.teardownVPP() + + ih := ifplugin_vppcalls.CompatibleInterfaceVppHandler(ctx.vppBinapi, logrus.NewLogger("test")) + const ifName = "loop1" + ifIdx, err := ih.AddLoopbackInterface(ifName) + if err != nil { + t.Fatalf("creating interface failed: %v", err) + } + t.Logf("interface created %v", ifIdx) + + ifIndexes := ifaceidx.NewIfaceIndex(logrus.NewLogger("test-if"), "test-if") + ifIndexes.Put(ifName, &ifaceidx.IfaceMetadata{SwIfIndex: ifIdx}) + vrfIndexes := vrfidx.NewVRFIndex(logrus.NewLogger("test-vrf"), "test-vrf") + vrfIndexes.Put("vrf1-ipv4", &vrfidx.VRFMetadata{Index: 0, Protocol: vpp_l3.VrfTable_IPV4}) + vrfIndexes.Put("vrf1-ipv6", &vrfidx.VRFMetadata{Index: 0, Protocol: vpp_l3.VrfTable_IPV6}) + + h := l3plugin_vppcalls.CompatibleL3VppHandler(ctx.vppBinapi, ifIndexes, vrfIndexes, logrus.NewLogger("test")) + + tests := []struct { + name string + newArpEntry vpp_l3.ARPEntry + }{ + {"static arp for ipv4", vpp_l3.ARPEntry{ + Interface: ifName, + IpAddress: "192.168.10.21", + PhysAddress: "59:6C:45:59:8E:BD", + Static: true, + }}, + {"nonstatic arp for ipv4", vpp_l3.ARPEntry{ + Interface: ifName, + IpAddress: "192.168.10.22", + PhysAddress: "6C:45:59:59:8E:BD", + Static: false, + }}, + {"nonstatic arp for ipv6", vpp_l3.ARPEntry{ + Interface: ifName, + IpAddress: "dead::1", + PhysAddress: "8E:BD:6C:45:59:59", + Static: false, + }}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + + arpentries, err := h.DumpArpEntries() + if err != nil { + t.Fatalf("dumping arpentries failed: %v", err) + } + arpentriescnt := len(arpentries) + t.Logf("%d arpentries dumped", arpentriescnt) + + err = h.VppAddArp(&test.newArpEntry) + if err != nil { + t.Fatalf("adding arpentry failed: %v", err) + } + t.Logf("arpentry added %+v", test.newArpEntry) + + arpentries, err = h.DumpArpEntries() + if err != nil { + t.Fatalf("dumping arpentries failed: %v", err) + } + arpentriescnt2 := len(arpentries) + t.Logf("%d arpentries dumped", arpentriescnt2) + + if arpentriescnt+1 != arpentriescnt2 { + t.Errorf("Number of arp entries after adding of one arp entry is not incremented by 1") + } + + newArpEntryIsPresent := false + for _, arpentry := range arpentries { + if (arpentry.Arp.Interface == test.newArpEntry.Interface) && (arpentry.Arp.IpAddress == test.newArpEntry.IpAddress) && (strings.ToLower(arpentry.Arp.PhysAddress) == strings.ToLower(test.newArpEntry.PhysAddress)) { + t.Logf("dumped arpentry %+v", arpentry) + newArpEntryIsPresent = true + break + } + } + + if !newArpEntryIsPresent { + t.Error("Added arp entry is not present in arp dump") + } + + err = h.VppDelArp(&test.newArpEntry) + if err != nil { + t.Fatalf("deleting arpentry failed: %v", err) + } + t.Logf("arpentry deleted") + + arpentries, err = h.DumpArpEntries() + if err != nil { + t.Fatalf("dumping arpentries failed: %v", err) + } + arpentriescnt3 := len(arpentries) + t.Logf("%d arpentries dumped", arpentriescnt3) + + if arpentriescnt2-1 != arpentriescnt3 { + t.Errorf("Number of arp entries after deleting of one arp entry is not decremented by 1") + } + + for _, arpentry := range arpentries { + if (arpentry.Arp.Interface == test.newArpEntry.Interface) && (arpentry.Arp.IpAddress == test.newArpEntry.IpAddress) && (strings.ToLower(arpentry.Arp.PhysAddress) == strings.ToLower(test.newArpEntry.PhysAddress)) { + t.Error("Added arp entry is still present in arp dump - should be deleted") + } + } + }) + } +}