2 * Copyright 2020 Intel Corporation, Inc
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
22 "ovn4nfv-k8s-plugin/internal/pkg/network"
23 "ovn4nfv-k8s-plugin/internal/pkg/ovn"
24 k8sv1alpha1 "ovn4nfv-k8s-plugin/pkg/apis/k8s/v1alpha1"
27 pb "ovn4nfv-k8s-plugin/internal/pkg/nfnNotify/proto"
29 "github.com/containernetworking/plugins/pkg/ns"
30 "github.com/docker/docker/client"
31 v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32 "k8s.io/client-go/kubernetes"
33 "sigs.k8s.io/controller-runtime/pkg/client/config"
34 logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
37 var log = logf.Log.WithName("chaining")
39 type RoutingInfo struct {
40 Name string // Name of the pod
41 Namespace string // Namespace of the Pod
42 Id string // Container ID for pod
43 Node string // Hostname where Pod is scheduled
44 LeftNetworkRoute k8sv1alpha1.Route // TODO: Update to support multiple networks
45 RightNetworkRoute k8sv1alpha1.Route // TODO: Update to support multiple networks
46 DynamicNetworkRoutes []k8sv1alpha1.Route
49 var chainRoutingInfo []RoutingInfo
51 // Calcuate route to get to left and right edge networks and other networks (not adjacent) in the chain
52 func calculateDeploymentRoutes(namespace, label string, pos int, num int, ln []k8sv1alpha1.RoutingNetwork, rn []k8sv1alpha1.RoutingNetwork, networkList, deploymentList []string) (r RoutingInfo, err error) {
55 var nextRightIP string
57 r.Namespace = namespace
58 // Get a config to talk to the apiserver
59 cfg, err := config.GetConfig()
61 return RoutingInfo{}, err
63 var k *kubernetes.Clientset
64 k, err = kubernetes.NewForConfig(cfg)
66 log.Error(err, "Error building Kuberenetes clientset")
67 return RoutingInfo{}, err
69 lo := v1.ListOptions{LabelSelector: label}
70 // List the Pods matching the Labels
71 pods, err := k.CoreV1().Pods(namespace).List(lo)
73 log.Error(err, "Deloyment with label not found", "label", label)
74 return RoutingInfo{}, err
76 // LOADBALANCER NOT YET SUPPORTED - Assuming deployment has only one Pod
77 if len(pods.Items) <= 0 {
78 log.Error(err, "Deloyment with label not found", "label", label)
79 return RoutingInfo{}, fmt.Errorf("Pod not found")
81 // Get the containerID of the first container
82 r.Id = strings.TrimPrefix(pods.Items[0].Status.ContainerStatuses[0].ContainerID, "docker://")
83 r.Name = pods.Items[0].GetName()
84 r.Node = pods.Items[0].Spec.NodeName
85 // Calcluate IP addresses for next neighbours on both sides
87 nextLeftIP = ln[0].GatewayIP
89 name := strings.Split(deploymentList[pos-1], "=")
90 nextLeftIP, err = ovn.GetIPAdressForPod(networkList[pos-1], name[1])
92 return RoutingInfo{}, err
96 nextRightIP = rn[0].GatewayIP
98 name := strings.Split(deploymentList[pos+1], "=")
99 nextRightIP, err = ovn.GetIPAdressForPod(networkList[pos], name[1])
101 return RoutingInfo{}, err
104 // Calcuate left right Route to be inserted in Pod
105 r.LeftNetworkRoute.Dst = ln[0].Subnet
106 r.LeftNetworkRoute.GW = nextLeftIP
107 r.RightNetworkRoute.Dst = rn[0].Subnet
108 r.RightNetworkRoute.GW = nextRightIP
109 // For each network that is not adjacent add route
110 for i := 0; i < len(networkList); i++ {
111 if i == pos || i == pos-1 {
114 var rt k8sv1alpha1.Route
115 rt.Dst, err = ovn.GetNetworkSubnet(networkList[i])
117 return RoutingInfo{}, err
124 r.DynamicNetworkRoutes = append(r.DynamicNetworkRoutes, rt)
128 //Add Default Route based on Right Network
129 rt := k8sv1alpha1.Route{
133 r.DynamicNetworkRoutes = append(r.DynamicNetworkRoutes, rt)
137 func CalculateRoutes(cr *k8sv1alpha1.NetworkChaining) ([]RoutingInfo, error) {
139 var deploymentList []string
140 var networkList []string
142 // TODO: Add Validation of Input to this function
143 ln := cr.Spec.RoutingSpec.LeftNetwork
144 rn := cr.Spec.RoutingSpec.RightNetwork
145 chains := strings.Split(cr.Spec.RoutingSpec.NetworkChain, ",")
147 for _, chain := range chains {
149 deploymentList = append(deploymentList, chain)
151 networkList = append(networkList, chain)
155 num := len(deploymentList)
156 log.Info("Display the num", "num", num)
157 log.Info("Display the ln", "ln", ln)
158 log.Info("Display the rn", "rn", rn)
159 log.Info("Display the networklist", "networkList", networkList)
160 log.Info("Display the deploymentlist", "deploymentList", deploymentList)
161 for i, deployment := range deploymentList {
162 r, err := calculateDeploymentRoutes(cr.Namespace, deployment, i, num, ln, rn, networkList, deploymentList)
166 chainRoutingInfo = append(chainRoutingInfo, r)
168 return chainRoutingInfo, nil
171 func ContainerAddRoute(containerPid int, route []*pb.RouteData) error {
172 str := fmt.Sprintf("/host/proc/%d/ns/net", containerPid)
174 hostNet, err := network.GetHostNetwork()
176 log.Error(err, "Failed to get host network")
180 nms, err := ns.GetNS(str)
182 log.Error(err, "Failed namesapce", "containerID", containerPid)
186 err = nms.Do(func(_ ns.NetNS) error {
187 podGW, err := network.GetDefaultGateway()
189 log.Error(err, "Failed to get pod default gateway")
193 stdout, stderr, err := ovn.RunIP("route", "add", hostNet, "via", podGW)
194 if err != nil && !strings.Contains(stderr, "RTNETLINK answers: File exists") {
195 log.Error(err, "Failed to ip route add", "stdout", stdout, "stderr", stderr)
199 for _, r := range route {
202 // Replace default route
203 if dst == "0.0.0.0" {
204 stdout, stderr, err := ovn.RunIP("route", "replace", "default", "via", gw)
206 log.Error(err, "Failed to ip route replace", "stdout", stdout, "stderr", stderr)
210 stdout, stderr, err := ovn.RunIP("route", "add", dst, "via", gw)
211 if err != nil && !strings.Contains(stderr, "RTNETLINK answers: File exists") {
212 log.Error(err, "Failed to ip route add", "stdout", stdout, "stderr", stderr)
220 log.Error(err, "Failed Netns Do", "containerID", containerPid)
226 func GetPidForContainer(id string) (int, error) {
227 cli, err := client.NewEnvClient()
229 fmt.Println("Unable to create docker client")
232 cli.NegotiateAPIVersion(context.Background())
233 cj, err := cli.ContainerInspect(context.Background(), id)
235 fmt.Println("Unable to Inspect docker container")
238 if cj.State.Pid == 0 {
239 return 0, fmt.Errorf("Container not found %s", id)
241 return cj.State.Pid, nil