-
Notifications
You must be signed in to change notification settings - Fork 0
/
link.go
186 lines (159 loc) · 5.96 KB
/
link.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/*
Copyright 2023 The Nephio Authors.
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 link
import (
"fmt"
"github.com/henderiw-nephio/wire-connector/pkg/pod"
"github.com/henderiw-nephio/wire-connector/pkg/xdp"
invv1alpha1 "github.com/nokia/k8s-ipam/apis/inv/v1alpha1"
log "github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/types"
)
type Link struct {
podManager pod.Manager
topologies map[string]struct{}
endpointA *Endpoint
endpointB *Endpoint
mtu int
xdp xdp.XDP
}
type LinkCtx struct {
PodManager pod.Manager
Topologies map[string]struct{}
XDP xdp.XDP
}
func NewLink(cr *invv1alpha1.Link, lctx *LinkCtx) *Link {
r := &Link{
podManager: lctx.PodManager,
xdp: lctx.XDP,
}
return &Link{
endpointA: r.getEndpoint(cr.Spec.Endpoints[0]),
endpointB: r.getEndpoint(cr.Spec.Endpoints[1]),
}
}
// getEndpoint returns an endpoint which provides context wrt
// cluster connectiivty: local or remote or unknown
// host conneciticity: local or remote or unknown; if local also the nspath of the container is initialized
func (r *Link) getEndpoint(epSpec invv1alpha1.LinkEndpointSpec) *Endpoint {
log.Info("getEndpoint", "epSpec", epSpec)
epCtx := &EndpointCtx{
IfName: epSpec.InterfaceName,
ClusterConnectivity: invv1alpha1.GetClusterConnectivity(epSpec.Topology, r.topologies),
XDP: r.xdp,
}
log.Info("getEndpoint", "clusterConn", invv1alpha1.GetClusterConnectivity(epSpec.Topology, r.topologies))
if epCtx.ClusterConnectivity != invv1alpha1.ClusterConnectivityLocal {
// this ep is on a remote cluster
epCtx.HostConnectivity = invv1alpha1.HostConnectivityRemote
return NewEndpoint(epCtx)
}
// this ep is on a local cluster
// for now namespace is default
podCtx, err := r.podManager.GetPod(types.NamespacedName{Namespace: "default", Name: epSpec.NodeName})
if err != nil {
log.Info("getEndpoint pod does not exist")
// pod does not exist
epCtx.HostConnectivity = invv1alpha1.HostConnectivityUnknown
} else {
epCtx.HostConnectivity = podCtx.HostConnectivity
epCtx.HostIP = podCtx.HostIP
if podCtx.HostConnectivity == invv1alpha1.HostConnectivityLocal {
epCtx.NsPath = podCtx.Containers[epSpec.NodeName].NSPath
}
}
log.Info("getEndpoint", "epCtx", epCtx)
return NewEndpoint(epCtx)
}
// IsReady returns true if cluster and host information of both endpoints are known
func (r *Link) IsReady() bool {
return !(r.endpointA.clusterConnectivity == invv1alpha1.ClusterConnectivityUnknown ||
r.endpointB.clusterConnectivity == invv1alpha1.ClusterConnectivityUnknown ||
r.endpointA.hostConnectivity == invv1alpha1.HostConnectivityUnknown ||
r.endpointB.hostConnectivity == invv1alpha1.HostConnectivityUnknown)
}
// IsCrossCluster returns true if the link is connected accross clusters
func (r *Link) IsCrossCluster() bool {
return r.endpointA.clusterConnectivity == invv1alpha1.ClusterConnectivityRemote ||
r.endpointB.clusterConnectivity == invv1alpha1.ClusterConnectivityRemote
}
// IsHostLocal returns true if both endpoints are on the same host
// the wiring in this case is all local to the host
func (r *Link) IsHostLocal() bool {
return r.endpointA.hostConnectivity == invv1alpha1.HostConnectivityLocal &&
r.endpointB.hostConnectivity == invv1alpha1.HostConnectivityLocal
}
// HasLocal returns true is one endpoint of the link is local to the host
// this indicated that a wiring activity is needed
func (r *Link) HasLocal() bool {
return r.endpointA.hostConnectivity == invv1alpha1.HostConnectivityLocal ||
r.endpointB.hostConnectivity == invv1alpha1.HostConnectivityLocal
}
// GetConn is a debugging facility
func (r *Link) GetConn() string {
return fmt.Sprintf("epA: cluster: %s, host: %s, epB: cluster: %s, host: %s",
r.endpointA.clusterConnectivity, r.endpointA.hostConnectivity,
r.endpointB.clusterConnectivity, r.endpointB.hostConnectivity,
)
}
// SetMtu sets the mtu on the link
func (r *Link) SetMtu(mtu int) {
r.mtu = mtu
}
// Deploy deploys the link on the host
// Creates a veth pair
// Per endpoint deploys either a veth itfce in the container namespace
// or a remote tunnel for which a veth pair gets cross connected with BPF XDP
func (r *Link) Deploy() error {
// get random names for veth sides as they will be created in root netns first
vethA, vethB, err := createVethPair()
if err != nil {
return err
}
r.endpointA.veth = vethA
r.endpointB.veth = vethB
if err := r.endpointA.Deploy(r.endpointB); err != nil {
return err
}
if err := r.endpointB.Deploy(r.endpointA); err != nil {
return err
}
return nil
}
func (r *Link) Destroy() error {
if err := r.endpointA.Destroy(); err != nil {
return err
}
if err := r.endpointB.Destroy(); err != nil {
return err
}
return nil
}
// Exists returns true if the link exists. Since we have 2 endpoints
// it might be some part does not exist. if only a part exists
// we return true
func (r *Link) Exists() bool {
// we need to recover the id of the veth pair
// we know the veth interface in the container ns.
// if it exists we return the index of the peer veth pair on the host
// otherwise the veth pair does not exist
// the peerIndex is used later to retrieve the peerID random name
// that is used for both the veth/tunn interface
r.endpointA.InitPeerVethIndex(r.endpointB)
r.endpointB.InitPeerVethIndex(r.endpointA)
log.Infof("endpointA: %v, endpointB: %v", r.endpointA, r.endpointB)
epAexists := r.endpointA.Exists()
epBExists := r.endpointB.Exists()
log.Infof("exists epAexists %t, epBexists %t", epAexists, epBExists)
return epAexists || epBExists
}