-
Notifications
You must be signed in to change notification settings - Fork 334
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Golang versioned ovn-kube-util (#113)
Signed-off-by: Pengfei Ni <feiskyer@gmail.com>
- Loading branch information
Showing
101 changed files
with
19,991 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package app | ||
|
||
import ( | ||
"net" | ||
"syscall" | ||
|
||
"github.com/vishvananda/netlink" | ||
"github.com/vishvananda/netlink/nl" | ||
) | ||
|
||
// addrList gets netlink.Addr for specified netlink.Link. | ||
// TODO: remove this after https://github.com/vishvananda/netlink/pull/226 is merged. | ||
func addrList(link netlink.Link, family int) ([]netlink.Addr, error) { | ||
h := &netlink.Handle{} | ||
req := nl.NewNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP) | ||
msg := nl.NewIfInfomsg(family) | ||
req.AddData(msg) | ||
|
||
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWADDR) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
indexFilter := 0 | ||
if link != nil { | ||
base := link.Attrs() | ||
|
||
// ensure index | ||
if base != nil && base.Index == 0 { | ||
newlink, _ := h.LinkByName(base.Name) | ||
if newlink != nil { | ||
base.Index = newlink.Attrs().Index | ||
} | ||
} | ||
indexFilter = base.Index | ||
} | ||
|
||
var res []netlink.Addr | ||
for _, m := range msgs { | ||
addr, msgFamily, ifindex, err := parseAddr(m) | ||
if err != nil { | ||
return res, err | ||
} | ||
|
||
if link != nil && ifindex != indexFilter { | ||
// Ignore messages from other interfaces | ||
continue | ||
} | ||
|
||
if family != netlink.FAMILY_ALL && msgFamily != family { | ||
continue | ||
} | ||
|
||
res = append(res, addr) | ||
} | ||
|
||
return res, nil | ||
} | ||
|
||
// parseAddr parses netlink.Addr from netlink message. | ||
func parseAddr(m []byte) (addr netlink.Addr, family, index int, err error) { | ||
msg := nl.DeserializeIfAddrmsg(m) | ||
|
||
family = -1 | ||
index = -1 | ||
|
||
attrs, err1 := nl.ParseRouteAttr(m[msg.Len():]) | ||
if err1 != nil { | ||
err = err1 | ||
return | ||
} | ||
|
||
family = int(msg.Family) | ||
index = int(msg.Index) | ||
|
||
var local, dst *net.IPNet | ||
for _, attr := range attrs { | ||
switch attr.Attr.Type { | ||
case syscall.IFA_ADDRESS: | ||
dst = &net.IPNet{ | ||
IP: attr.Value, | ||
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)), | ||
} | ||
addr.Peer = dst | ||
case syscall.IFA_LOCAL: | ||
local = &net.IPNet{ | ||
IP: attr.Value, | ||
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)), | ||
} | ||
addr.IPNet = local | ||
case syscall.IFA_BROADCAST: | ||
addr.Broadcast = attr.Value | ||
case syscall.IFA_LABEL: | ||
addr.Label = string(attr.Value[:len(attr.Value)-1]) | ||
case netlink.IFA_FLAGS: | ||
addr.Flags = int(nl.NativeEndian().Uint32(attr.Value[0:4])) | ||
case nl.IFA_CACHEINFO: | ||
ci := nl.DeserializeIfaCacheInfo(attr.Value) | ||
addr.PreferedLft = int(ci.IfaPrefered) | ||
addr.ValidLft = int(ci.IfaValid) | ||
} | ||
} | ||
|
||
// IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS | ||
if local != nil { | ||
addr.IPNet = local | ||
} else { | ||
addr.IPNet = dst | ||
} | ||
addr.Scope = int(msg.Scope) | ||
|
||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
package app | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"strings" | ||
"syscall" | ||
|
||
"github.com/Sirupsen/logrus" | ||
"github.com/urfave/cli" | ||
"github.com/vishvananda/netlink" | ||
"k8s.io/apimachinery/pkg/util/errors" | ||
|
||
"github.com/openvswitch/ovn-kubernetes/go-controller/pkg/util" | ||
) | ||
|
||
// NicsToBridgeCommand creates ovs bridge for provided nic interfaces. | ||
var NicsToBridgeCommand = cli.Command{ | ||
Name: "nics-to-bridge", | ||
Usage: "Create ovs bridge for nic interfaces", | ||
Flags: []cli.Flag{}, | ||
Action: func(context *cli.Context) error { | ||
args := context.Args() | ||
if len(args) == 0 { | ||
return fmt.Errorf("Please specify list of nic interfaces") | ||
} | ||
|
||
var errorList []error | ||
for _, nic := range args { | ||
if err := nicToBridge(nic); err != nil { | ||
errorList = append(errorList, err) | ||
} | ||
} | ||
|
||
return errors.NewAggregate(errorList) | ||
}, | ||
} | ||
|
||
func getBridgeName(iface string) string { | ||
return fmt.Sprintf("br%s", iface) | ||
} | ||
|
||
func saveIPAddress(iface, bridge netlink.Link, addrs []netlink.Addr) error { | ||
for i := range addrs { | ||
addr := addrs[i] | ||
|
||
// Remove from old interface | ||
if err := netlink.AddrDel(iface, &addr); err != nil { | ||
logrus.Errorf("Remove addr from %q failed: %v", iface.Attrs().Name, err) | ||
return err | ||
} | ||
|
||
// Add to ovs bridge | ||
addr.Label = bridge.Attrs().Name | ||
if err := netlink.AddrAdd(bridge, &addr); err != nil { | ||
logrus.Errorf("Add addr to bridge %q failed: %v", bridge.Attrs().Name, err) | ||
return err | ||
} | ||
logrus.Infof("Successfully saved addr %q to bridge %q", addr.String(), bridge.Attrs().Name) | ||
} | ||
|
||
return netlink.LinkSetUp(bridge) | ||
} | ||
|
||
func saveRoute(iface, bridge netlink.Link, routes []netlink.Route) error { | ||
for i := range routes { | ||
route := routes[i] | ||
|
||
// Remove from old interface | ||
if err := netlink.RouteDel(&route); err != nil && !strings.Contains(err.Error(), "no such process") { | ||
logrus.Errorf("Remove route from %q failed: %v", iface.Attrs().Name, err) | ||
return err | ||
} | ||
|
||
// Add to ovs bridge | ||
route.LinkIndex = bridge.Attrs().Index | ||
if err := netlink.RouteAdd(&route); err != nil && !os.IsExist(err) { | ||
logrus.Errorf("Add route to bridge %q failed: %v", bridge.Attrs().Name, err) | ||
return err | ||
} | ||
|
||
logrus.Infof("Successfully saved route %q", route.String()) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func nicToBridge(iface string) error { | ||
ifaceLink, err := netlink.LinkByName(iface) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
bridge := getBridgeName(iface) | ||
stdout, stderr, err := util.RunOVSVsctl( | ||
"--", "--may-exist", "add-br", bridge, | ||
"--", "br-set-external-id", bridge, "bridge-id", bridge, | ||
"--", "set", "bridge", bridge, "fail-mode=standalone", | ||
fmt.Sprintf("other_config:hwaddr=%s", ifaceLink.Attrs().HardwareAddr), | ||
"--", "add-port", bridge, iface) | ||
if err != nil { | ||
logrus.Errorf("Failed to create OVS bridge, stdout: %q, stderr: %q, error: %v", stdout, stderr, err) | ||
return err | ||
} | ||
logrus.Infof("Successfully created OVS bridge %q", bridge) | ||
|
||
// Get ip addresses and routes before any real operations. | ||
// Note: addrList is a workround for also getting broadcast addr. | ||
// TODO: switch to netlink.AddrList after https://github.com/vishvananda/netlink/pull/226 is merged. | ||
addrs, err := addrList(ifaceLink, syscall.AF_INET) | ||
if err != nil { | ||
return err | ||
} | ||
routes, err := netlink.RouteList(ifaceLink, syscall.AF_INET) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
bridgeLink, err := netlink.LinkByName(bridge) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// save ip addresses to bridge. | ||
if err = saveIPAddress(ifaceLink, bridgeLink, addrs); err != nil { | ||
return err | ||
} | ||
|
||
// save routes to bridge. | ||
if err = saveRoute(ifaceLink, bridgeLink, routes); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package main | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/Sirupsen/logrus" | ||
"github.com/openvswitch/ovn-kubernetes/go-controller/cmd/ovn-kube-util/app" | ||
"github.com/urfave/cli" | ||
) | ||
|
||
func main() { | ||
c := cli.NewApp() | ||
c.Name = "ovn-kube-util" | ||
c.Usage = "Utils for kubernetes ovn" | ||
c.Version = "0.0.1" | ||
|
||
c.Commands = []cli.Command{ | ||
app.NicsToBridgeCommand, | ||
} | ||
|
||
if err := c.Run(os.Args); err != nil { | ||
logrus.Fatal(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package util | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"os/exec" | ||
) | ||
|
||
const ( | ||
ovsCommandTimeout = 5 | ||
ovsVsctlCommand = "ovs-vsctl" | ||
) | ||
|
||
// RunOVSVsctl runs a command via ovs-vsctl. | ||
func RunOVSVsctl(args ...string) (string, string, error) { | ||
cmdPath, err := exec.LookPath(ovsVsctlCommand) | ||
if err != nil { | ||
return "", "", err | ||
} | ||
|
||
stdout := &bytes.Buffer{} | ||
stderr := &bytes.Buffer{} | ||
cmdArgs := []string{fmt.Sprintf("--timeout=%d", ovsCommandTimeout)} | ||
cmdArgs = append(cmdArgs, args...) | ||
cmd := exec.Command(cmdPath, cmdArgs...) | ||
cmd.Stdout = stdout | ||
cmd.Stderr = stderr | ||
|
||
err = cmd.Run() | ||
return stdout.String(), stderr.String(), err | ||
} |
Oops, something went wrong.