Skip to content

Commit 6a4c197

Browse files
committed
Move to json storage, address pblindex issue
This patch changes the way we persist the data on disk when running Calico/VPP. Instead of using struc and binary format we transition to json files. Size should not be an issue as number of pods per node are typically low (~100). This will make troubleshooting easier and errors clearer when parsing fails. We thus remove the /bin/debug troubleshooting utility as the data format is not human readable. Doing this, we address an issue where PBL indexes were reused upon dataplane restart, as they were stored in a list. We now will use a map to retain the containerIP mapping. We also split the configuration from runtime spec in LocalPodSpec and add a step to clear it when corresponding VRFs are not found in VPP. Finally we address an issue where uRPF was not properly set up for ipv6. Signed-off-by: Nathan Skrzypczak <nathan.skrzypczak@gmail.com>
1 parent 84ed1e9 commit 6a4c197

25 files changed

Lines changed: 509 additions & 640 deletions

calico-vpp-agent/Dockerfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ FROM ubuntu:22.04
33
LABEL maintainer="aloaugus@cisco.com"
44

55
ADD bin/gobgp /bin/gobgp
6-
ADD bin/debug /bin/debug
76
ADD version /etc/calicovppversion
87
ADD bin/felix-api-proxy /bin/felix-api-proxy
98
ADD bin/calico-vpp-agent /bin/calico-vpp-agent

calico-vpp-agent/Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ felix-api-proxy: bin
2323

2424
build: felix-api-proxy bin
2525
${DOCKER_RUN} go build -o ./bin/calico-vpp-agent ./cmd
26-
${DOCKER_RUN} go build -o ./bin/debug ./cmd/debug-state
2726

2827
gobgp: bin
2928
${DOCKER_RUN} go build -o ./bin/gobgp github.com/osrg/gobgp/v3/cmd/gobgp/

calico-vpp-agent/cmd/debug-state/debug-state.go

Lines changed: 0 additions & 43 deletions
This file was deleted.

calico-vpp-agent/cni/cni_pod_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ var _ = Describe("Pod-related functionality of CNI", func() {
182182
Workload: &cniproto.WorkloadIDs{
183183
Annotations: map[string]string{
184184
// needed just for setting up steering of traffic to default Tun/Tap and to secondary Memif
185-
cni.VppAnnotationPrefix + cni.MemifPortAnnotation: fmt.Sprintf("tcp:%d-%d,udp:%d-%d",
185+
config.VppAnnotationPrefix + config.MemifPortAnnotation: fmt.Sprintf("tcp:%d-%d,udp:%d-%d",
186186
memifTCPPortStart, memifTCPPortEnd, memifUDPPortStart, memifUDPPortEnd),
187187
},
188188
},
@@ -418,7 +418,7 @@ var _ = Describe("Pod-related functionality of CNI", func() {
418418
Workload: &cniproto.WorkloadIDs{
419419
Annotations: map[string]string{
420420
// needed just for setting up steering of traffic to default Tun/Tap and to secondary Memif
421-
cni.VppAnnotationPrefix + cni.MemifPortAnnotation: fmt.Sprintf("tcp:%d-%d,udp:%d-%d",
421+
config.VppAnnotationPrefix + config.MemifPortAnnotation: fmt.Sprintf("tcp:%d-%d,udp:%d-%d",
422422
memifTCPPortStart, memifTCPPortEnd, memifUDPPortStart, memifUDPPortEnd),
423423
},
424424
},

calico-vpp-agent/cni/cni_server.go

Lines changed: 19 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -72,19 +72,6 @@ func swIfIdxToIfName(idx uint32) string {
7272
return fmt.Sprintf("vpp-tun-%d", idx)
7373
}
7474

75-
func getHostEndpointProto(proto string) types.IPProto {
76-
switch proto {
77-
case "udp":
78-
return types.UDP
79-
case "sctp":
80-
return types.SCTP
81-
case "tcp":
82-
return types.TCP
83-
default:
84-
return types.TCP
85-
}
86-
}
87-
8875
func (s *Server) SetFelixConfig(felixConfig *felixConfig.Config) {
8976
s.tuntapDriver.SetFelixConfig(felixConfig)
9077
}
@@ -93,127 +80,20 @@ func (s *Server) SetOurBGPSpec(nodeBGPSpec *common.LocalNodeSpec) {
9380
s.nodeBGPSpec = nodeBGPSpec
9481
}
9582

96-
func (s *Server) newLocalPodSpecFromAdd(request *cniproto.AddRequest) (*storage.LocalPodSpec, error) {
97-
podSpec := storage.LocalPodSpec{
98-
InterfaceName: request.GetInterfaceName(),
99-
NetnsName: request.GetNetns(),
100-
AllowIpForwarding: request.GetSettings().GetAllowIpForwarding(),
101-
Routes: make([]storage.LocalIPNet, 0),
102-
ContainerIps: make([]storage.LocalIP, 0),
103-
Mtu: int(request.GetSettings().GetMtu()),
104-
105-
IfPortConfigs: make([]storage.LocalIfPortConfigs, 0),
106-
107-
OrchestratorID: request.Workload.Orchestrator,
108-
WorkloadID: request.Workload.Namespace + "/" + request.Workload.Pod,
109-
EndpointID: request.Workload.Endpoint,
110-
HostPorts: make([]storage.HostPortBinding, 0),
111-
112-
/* defaults */
113-
IfSpec: GetDefaultIfSpec(true /* isL3 */),
114-
PBLMemifSpec: GetDefaultIfSpec(false /* isL3 */),
115-
116-
V4VrfId: vpplink.InvalidID,
117-
V6VrfId: vpplink.InvalidID,
118-
119-
MemifSwIfIndex: vpplink.InvalidID,
120-
TunTapSwIfIndex: vpplink.InvalidID,
121-
122-
NetworkName: request.DataplaneOptions["network_name"],
123-
}
124-
125-
if podSpec.NetworkName != "" {
126-
if !*config.GetCalicoVppFeatureGates().MultinetEnabled {
127-
return nil, fmt.Errorf("enable multinet in config for multiple networks")
128-
}
129-
if isMemif(podSpec.InterfaceName) {
130-
if !*config.GetCalicoVppFeatureGates().MemifEnabled {
131-
return nil, fmt.Errorf("enable memif in config for memif interfaces")
132-
}
133-
podSpec.EnableMemif = true
134-
podSpec.DefaultIfType = storage.VppIfTypeMemif
135-
podSpec.IfSpec = GetDefaultIfSpec(false)
136-
}
137-
}
138-
139-
for _, port := range request.Workload.Ports {
140-
hostIP := net.ParseIP(port.HostIp)
141-
hostPort := uint16(port.HostPort)
142-
if hostPort != 0 && hostIP != nil && !hostIP.IsUnspecified() {
143-
podSpec.HostPorts = append(podSpec.HostPorts, storage.HostPortBinding{
144-
HostPort: hostPort,
145-
HostIP: hostIP,
146-
ContainerPort: uint16(port.Port),
147-
Protocol: getHostEndpointProto(port.Protocol),
148-
})
149-
} else if hostPort != 0 {
150-
// default to node IP
151-
podSpec.HostPorts = append(podSpec.HostPorts, storage.HostPortBinding{
152-
HostPort: hostPort,
153-
HostIP: net.ParseIP(s.nodeBGPSpec.IPv4Address.IP.String()),
154-
ContainerPort: uint16(port.Port),
155-
Protocol: getHostEndpointProto(port.Protocol),
156-
})
157-
}
158-
}
159-
for _, routeStr := range request.GetContainerRoutes() {
160-
_, route, err := net.ParseCIDR(routeStr)
161-
if err != nil {
162-
return nil, errors.Wrapf(err, "Cannot parse container route %s", routeStr)
163-
}
164-
podSpec.Routes = append(podSpec.Routes, storage.LocalIPNet{
165-
IP: route.IP,
166-
Mask: route.Mask,
167-
})
168-
}
83+
func (s *Server) Add(ctx context.Context, request *cniproto.AddRequest) (*cniproto.AddReply, error) {
84+
/* We don't support request.GetDesiredHostInterfaceName() */
85+
podSpec, err := storage.NewLocalPodSpecFromAdd(request, s.nodeBGPSpec)
16986
if podSpec.NetworkName != "" {
17087
value, ok := s.networkDefinitions.Load(podSpec.NetworkName)
17188
if !ok {
172-
s.log.Errorf("trying to create a pod in an unexisting network %s", podSpec.NetworkName)
89+
return nil, fmt.Errorf("trying to create a pod in an unexisting network %s", podSpec.NetworkName)
17390
} else {
17491
_, route, err := net.ParseCIDR(value.(*watchers.NetworkDefinition).Range)
17592
if err == nil {
176-
podSpec.Routes = append(podSpec.Routes, storage.LocalIPNet{
177-
IP: route.IP,
178-
Mask: route.Mask,
179-
})
93+
podSpec.Routes = append(podSpec.Routes, *route)
18094
}
18195
}
18296
}
183-
for _, requestContainerIP := range request.GetContainerIps() {
184-
containerIp, _, err := net.ParseCIDR(requestContainerIP.GetAddress())
185-
if err != nil {
186-
return nil, fmt.Errorf("Cannot parse address: %s", requestContainerIP.GetAddress())
187-
}
188-
// We ignore the prefix len set on the address,
189-
// for a tun it doesn't make sense
190-
podSpec.ContainerIps = append(podSpec.ContainerIps, storage.LocalIP{IP: containerIp})
191-
}
192-
workload := request.GetWorkload()
193-
if workload != nil {
194-
err := s.ParsePodAnnotations(&podSpec, workload.Annotations)
195-
if err != nil {
196-
return nil, errors.Wrapf(err, "Cannot parse pod Annotations")
197-
}
198-
}
199-
200-
if podSpec.DefaultIfType == storage.VppIfTypeUnknown {
201-
podSpec.DefaultIfType = storage.VppIfTypeTunTap
202-
}
203-
204-
return &podSpec, nil
205-
}
206-
207-
func NewLocalPodSpecFromDel(request *cniproto.DelRequest) *storage.LocalPodSpec {
208-
return &storage.LocalPodSpec{
209-
InterfaceName: request.GetInterfaceName(),
210-
NetnsName: request.GetNetns(),
211-
}
212-
}
213-
214-
func (s *Server) Add(ctx context.Context, request *cniproto.AddRequest) (*cniproto.AddReply, error) {
215-
/* We don't support request.GetDesiredHostInterfaceName() */
216-
podSpec, err := s.newLocalPodSpecFromAdd(request)
21797
if err != nil {
21898
s.log.Errorf("Error parsing interface add request %v %v", request, err)
21999
return &cniproto.AddReply{
@@ -248,7 +128,7 @@ func (s *Server) Add(ctx context.Context, request *cniproto.AddRequest) (*cnipro
248128
}, nil
249129
}
250130
if len(config.GetCalicoVppInitialConfig().RedirectToHostRules) != 0 && podSpec.NetworkName == "" {
251-
err := s.AddRedirectToHostToInterface(podSpec.TunTapSwIfIndex)
131+
err := s.AddRedirectToHostToInterface(podSpec.Status.TunTapSwIfIndex)
252132
if err != nil {
253133
return nil, err
254134
}
@@ -311,7 +191,7 @@ func (s *Server) rescanState() {
311191
s.lock.Lock()
312192
defer s.lock.Unlock()
313193
for _, podSpec := range podSpecs {
314-
/* copy podSpec as a pointer to it will be sent over the event chan */
194+
// we copy podSpec as a pointer to it will be sent over the event chan
315195
podSpecCopy := podSpec.Copy()
316196
_, err := s.AddVppInterface(&podSpecCopy, false /* doHostSideConf */)
317197
switch err.(type) {
@@ -324,7 +204,7 @@ func (s *Server) rescanState() {
324204
s.log.Errorf("Interface add failed %s : %v", podSpecCopy.String(), err)
325205
}
326206
if len(config.GetCalicoVppInitialConfig().RedirectToHostRules) != 0 && podSpecCopy.NetworkName == "" {
327-
err := s.AddRedirectToHostToInterface(podSpecCopy.TunTapSwIfIndex)
207+
err := s.AddRedirectToHostToInterface(podSpecCopy.Status.TunTapSwIfIndex)
328208
if err != nil {
329209
s.log.Error(err)
330210
}
@@ -355,9 +235,9 @@ func (s *Server) AddRedirectToHostToInterface(swIfIndex uint32) error {
355235
}
356236

357237
func (s *Server) Del(ctx context.Context, request *cniproto.DelRequest) (*cniproto.DelReply, error) {
358-
partialPodSpec := NewLocalPodSpecFromDel(request)
238+
podSpecKey := storage.LocalPodSpecKey(request.GetNetns(), request.GetInterfaceName())
359239
// Only try to delete the device if a namespace was passed in.
360-
if partialPodSpec.NetnsName == "" {
240+
if request.GetNetns() == "" {
361241
s.log.Debugf("no netns passed, skipping")
362242
return &cniproto.DelReply{
363243
Successful: true,
@@ -366,17 +246,17 @@ func (s *Server) Del(ctx context.Context, request *cniproto.DelRequest) (*cnipro
366246
s.lock.Lock()
367247
defer s.lock.Unlock()
368248

369-
s.log.Infof("pod(del) key=%s", partialPodSpec.Key())
370-
initialSpec, ok := s.podInterfaceMap[partialPodSpec.Key()]
249+
s.log.Infof("pod(del) key=%s", podSpecKey)
250+
initialSpec, ok := s.podInterfaceMap[podSpecKey]
371251
if !ok {
372-
s.log.Warnf("Unknown pod to delete key=%s", partialPodSpec.Key())
252+
s.log.Warnf("Unknown pod to delete key=%s", podSpecKey)
373253
} else {
374254
s.log.Infof("pod(del) spec=%s", initialSpec.String())
375255
s.DelVppInterface(&initialSpec)
376256
s.log.Infof("pod(del) Done! spec=%s", initialSpec.String())
377257
}
378258

379-
delete(s.podInterfaceMap, initialSpec.Key())
259+
delete(s.podInterfaceMap, podSpecKey)
380260
err := storage.PersistCniServerState(s.podInterfaceMap, config.CniServerStateFile+fmt.Sprint(storage.CniServerStateFileVersion))
381261
if err != nil {
382262
s.log.Errorf("CNI state persist errored %v", err)
@@ -451,16 +331,16 @@ forloop:
451331
}
452332

453333
for _, podSpec := range s.podInterfaceMap {
454-
NeededSnat := podSpec.NeedsSnat
334+
NeededSnat := podSpec.Status.NeedsSnat
455335
for _, containerIP := range podSpec.GetContainerIps() {
456-
podSpec.NeedsSnat = podSpec.NeedsSnat || s.policyServerIpam.IPNetNeedsSNAT(containerIP)
336+
podSpec.Status.NeedsSnat = podSpec.Status.NeedsSnat || s.policyServerIpam.IPNetNeedsSNAT(containerIP)
457337
}
458-
if NeededSnat != podSpec.NeedsSnat {
459-
for _, swIfIndex := range []uint32{podSpec.LoopbackSwIfIndex, podSpec.TunTapSwIfIndex, podSpec.MemifSwIfIndex} {
338+
if NeededSnat != podSpec.Status.NeedsSnat {
339+
for _, swIfIndex := range []uint32{podSpec.Status.LoopbackSwIfIndex, podSpec.Status.TunTapSwIfIndex, podSpec.Status.MemifSwIfIndex} {
460340
if swIfIndex != vpplink.InvalidID {
461341
s.log.Infof("Enable/Disable interface[%d] SNAT", swIfIndex)
462342
for _, ipFamily := range vpplink.IpFamilies {
463-
err := s.vpp.EnableDisableCnatSNAT(swIfIndex, ipFamily.IsIp6, podSpec.NeedsSnat)
343+
err := s.vpp.EnableDisableCnatSNAT(swIfIndex, ipFamily.IsIp6, podSpec.Status.NeedsSnat)
464344
if err != nil {
465345
return errors.Wrapf(err, "Error enabling/disabling %s snat", ipFamily.Str)
466346
}

0 commit comments

Comments
 (0)