9 "ovn4nfv-k8s-plugin/internal/pkg/config"
10 "ovn4nfv-k8s-plugin/internal/pkg/network"
11 "ovn4nfv-k8s-plugin/internal/pkg/ovn"
15 "github.com/containernetworking/cni/pkg/types/current"
16 "github.com/containernetworking/plugins/pkg/ip"
17 "github.com/containernetworking/plugins/pkg/ns"
18 "github.com/prometheus/common/log"
19 "github.com/sirupsen/logrus"
20 "github.com/vishvananda/netlink"
23 func renameLink(curName, newName string) error {
24 link, err := netlink.LinkByName(curName)
29 if err := netlink.LinkSetDown(link); err != nil {
32 if err := netlink.LinkSetName(link, newName); err != nil {
35 if err := netlink.LinkSetUp(link); err != nil {
43 func CreateNodeOVSInternalPort(nodeintfipaddr, nodeintfmacaddr, node string) error {
44 nodeName := strings.ToLower(node)
45 nodeOVSInternalIntfName := config.GetNodeIntfName(nodeName)
47 hwAddr, err := net.ParseMAC(nodeintfmacaddr)
49 logrus.Errorf("Error is converting %q to net hwaddr: %v", nodeOVSInternalIntfName, err)
50 return fmt.Errorf("Error is converting %q to net hwaddr: %v", nodeOVSInternalIntfName, err)
54 "add-port", "br-int", nodeOVSInternalIntfName, "--", "set",
55 "interface", nodeOVSInternalIntfName, "type=internal",
56 fmt.Sprintf("mac_in_use=%s", strings.ReplaceAll(hwAddr.String(), ":", "\\:")),
57 fmt.Sprintf("mac=%s", strings.ReplaceAll(hwAddr.String(), ":", "\\:")),
58 fmt.Sprintf("external_ids:iface-id=%s", nodeOVSInternalIntfName),
60 logrus.Infof("ovs-vsctl args - %v", ovsArgs)
63 out, err := exec.Command("ovs-vsctl", ovsArgs...).CombinedOutput()
65 logrus.Errorf("failure in creating Node OVS internal port - %s: %v - %q", nodeOVSInternalIntfName, err, string(out))
66 return fmt.Errorf("failure in creating Node OVS internal port - %s: %v - %q", nodeOVSInternalIntfName, err, string(out))
68 logrus.Infof("ovs-vsctl args - %v output:%v", ovsArgs, string(out))
70 link, err := netlink.LinkByName(nodeOVSInternalIntfName)
72 logrus.Errorf("failed to get netlink for Node OVS internal port %s: %v", nodeOVSInternalIntfName, err)
73 return fmt.Errorf("failed to get netlink for Node OVS internal port %s: %v", nodeOVSInternalIntfName, err)
76 if err := netlink.LinkSetUp(link); err != nil {
77 logrus.Errorf("failed to set up netlink for Node OVS internal port %s: %v", nodeOVSInternalIntfName, err)
78 return fmt.Errorf("failed to set up netlink for Node OVS internal port %s: %v", nodeOVSInternalIntfName, err)
81 addr, err := netlink.ParseAddr(nodeintfipaddr)
83 logrus.Errorf("failed to parse IP addr %s: %v", nodeintfipaddr, err)
84 return fmt.Errorf("failed to parse IP addr %s: %v", nodeintfipaddr, err)
86 err = netlink.AddrAdd(link, addr)
88 logrus.Errorf("failed to parse IP addr %s: %v", nodeintfipaddr, err)
89 return fmt.Errorf("failed to add IP addr %s to %s: %v", nodeintfipaddr, nodeOVSInternalIntfName, err)
92 err = network.SetupAndEnsureIPTables(network.MasqRules(nodeOVSInternalIntfName))
94 logrus.Errorf("failed to apply snat rule for %s: %v", nodeOVSInternalIntfName, err)
95 return fmt.Errorf("failed to apply snat rule for %s: %v", nodeOVSInternalIntfName, err)
101 func setupInterface(netns ns.NetNS, containerID, ifName, macAddress, ipAddress, gatewayIP, defaultGateway string, idx, mtu int, isDefaultGW bool) (*current.Interface, *current.Interface, error) {
102 hostIface := ¤t.Interface{}
103 contIface := ¤t.Interface{}
106 if defaultGateway == "false" && isDefaultGW == true && ifName == "eth0" {
108 hostNet, err = network.GetHostNetwork()
110 log.Error(err, "Failed to get host network")
111 return nil, nil, fmt.Errorf("failed to get host network: %v", err)
115 var oldHostVethName string
116 err := netns.Do(func(hostNS ns.NetNS) error {
117 // create the veth pair in the container and move host end into host netns
118 hostVeth, containerVeth, err := ip.SetupVeth(ifName, mtu, hostNS)
120 return fmt.Errorf("failed to setup veth %s: %v", ifName, err)
123 hostIface.Mac = hostVeth.HardwareAddr.String()
124 contIface.Name = containerVeth.Name
126 link, err := netlink.LinkByName(contIface.Name)
128 return fmt.Errorf("failed to lookup %s: %v", contIface.Name, err)
131 hwAddr, err := net.ParseMAC(macAddress)
133 return fmt.Errorf("failed to parse mac address for %s: %v", contIface.Name, err)
135 err = netlink.LinkSetHardwareAddr(link, hwAddr)
137 return fmt.Errorf("failed to add mac address %s to %s: %v", macAddress, contIface.Name, err)
139 contIface.Mac = macAddress
140 contIface.Sandbox = netns.Path()
142 addr, err := netlink.ParseAddr(ipAddress)
146 err = netlink.AddrAdd(link, addr)
148 return fmt.Errorf("failed to add IP addr %s to %s: %v", ipAddress, contIface.Name, err)
151 if defaultGateway == "true" {
152 gw := net.ParseIP(gatewayIP)
154 return fmt.Errorf("parse ip of gateway failed")
156 err = ip.AddRoute(nil, gw, link)
158 logrus.Errorf("ip.AddRoute failed %v gw %v link %v", err, gw, link)
163 if defaultGateway == "false" && isDefaultGW == true && ifName == "eth0" {
164 stdout, stderr, err := ovn.RunIP("route", "add", hostNet, "via", gatewayIP)
165 if err != nil && !strings.Contains(stderr, "RTNETLINK answers: File exists") {
166 logrus.Errorf("Failed to ip route add stout %s, stderr %s, err %v", stdout, stderr, err)
167 return fmt.Errorf("Failed to ip route add stout %s, stderr %s, err %v", stdout, stderr, err)
171 oldHostVethName = hostVeth.Name
179 // rename the host end of veth pair
180 hostIface.Name = containerID[:14] + strconv.Itoa(idx)
181 if err := renameLink(oldHostVethName, hostIface.Name); err != nil {
182 return nil, nil, fmt.Errorf("failed to rename %s to %s: %v", oldHostVethName, hostIface.Name, err)
185 return hostIface, contIface, nil
188 // ConfigureInterface sets up the container interface
189 var ConfigureInterface = func(containerNetns, containerID, ifName, namespace, podName, macAddress, ipAddress, gatewayIP, interfaceName, defaultGateway string, idx, mtu int, isDefaultGW bool) ([]*current.Interface, error) {
190 netns, err := ns.GetNS(containerNetns)
192 return nil, fmt.Errorf("failed to open netns %q: %v", containerNetns, err)
197 if interfaceName != "*" {
198 ifaceID = fmt.Sprintf("%s_%s_%s", namespace, podName, interfaceName)
200 ifaceID = fmt.Sprintf("%s_%s", namespace, podName)
201 interfaceName = ifName
203 hostIface, contIface, err := setupInterface(netns, containerID, interfaceName, macAddress, ipAddress, gatewayIP, defaultGateway, idx, mtu, isDefaultGW)
209 "add-port", "br-int", hostIface.Name, "--", "set",
210 "interface", hostIface.Name,
211 fmt.Sprintf("external_ids:attached_mac=%s", macAddress),
212 fmt.Sprintf("external_ids:iface-id=%s", ifaceID),
213 fmt.Sprintf("external_ids:ip_address=%s", ipAddress),
214 fmt.Sprintf("external_ids:sandbox=%s", containerID),
218 out, err = exec.Command("ovs-vsctl", ovsArgs...).CombinedOutput()
220 return nil, fmt.Errorf("failure in plugging pod interface: %v\n %q", err, string(out))
223 return []*current.Interface{hostIface, contIface}, nil
226 func setupRoute(netns ns.NetNS, dst, gw, dev string) error {
227 // Add Route to the namespace
228 err := netns.Do(func(_ ns.NetNS) error {
229 dstAddr, dstAddrNet, _ := net.ParseCIDR(dst)
230 ipNet := net.IPNet{IP: dstAddr, Mask: dstAddrNet.Mask}
231 link, err := netlink.LinkByName(dev)
232 err = ip.AddRoute(&ipNet, net.ParseIP(gw), link)
234 logrus.Errorf("ip.AddRoute failed %v dst %v gw %v", err, dst, gw)
241 // ConfigureRoute sets up the container routes
242 var ConfigureRoute = func(containerNetns, dst, gw, dev string) error {
243 netns, err := ns.GetNS(containerNetns)
245 return fmt.Errorf("failed to open netns %q: %v", containerNetns, err)
248 err = setupRoute(netns, dst, gw, dev)
252 // PlatformSpecificCleanup deletes the OVS port
253 func PlatformSpecificCleanup(ifaceName string) (bool, error) {
256 "del-port", "br-int", ifaceName,
258 out, err := exec.Command("ovs-vsctl", ovsArgs...).CombinedOutput()
259 if err != nil && !strings.Contains(string(out), "no port named") {
260 // DEL should be idempotent; don't return an error just log it
261 logrus.Warningf("failed to delete OVS port %s: %v\n %q", ifaceName, err, string(out))