diff --git a/handle_unspecified.go b/handle_unspecified.go index 693ca0a5..e8c89564 100644 --- a/handle_unspecified.go +++ b/handle_unspecified.go @@ -271,6 +271,10 @@ func (h *Handle) RouteReplace(route *Route) error { return ErrNotImplemented } +func (h *Handle) RouteChange(route *Route) error { + return ErrNotImplemented +} + func (h *Handle) RuleAdd(rule *Rule) error { return ErrNotImplemented } diff --git a/netlink_unspecified.go b/netlink_unspecified.go index c80b05e9..a3b314d6 100644 --- a/netlink_unspecified.go +++ b/netlink_unspecified.go @@ -212,6 +212,10 @@ func RouteReplace(route *Route) error { return ErrNotImplemented } +func RouteChange(route *Route) error { + return ErrNotImplemented +} + func XfrmPolicyAdd(policy *XfrmPolicy) error { return ErrNotImplemented } diff --git a/route_linux.go b/route_linux.go index 5db8f1d6..456560b8 100644 --- a/route_linux.go +++ b/route_linux.go @@ -702,6 +702,21 @@ func (h *Handle) RouteReplace(route *Route) error { return err } +// RouteChange will change a route on the system. +// Equivalent to: `ip route change $route` +func RouteChange(route *Route) error { + return pkgHandle.RouteChange(route) +} + +// RouteChange will change a route on the system. +// Equivalent to: `ip route change $route` +func (h *Handle) RouteChange(route *Route) error { + flags := unix.NLM_F_REPLACE | unix.NLM_F_ACK + req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags) + _, err := h.routeHandle(route, req, nl.NewRtMsg()) + return err +} + // RouteDel will delete a route from the system. // Equivalent to: `ip route del $route` func RouteDel(route *Route) error { diff --git a/route_test.go b/route_test.go index 649f8a02..ca996589 100644 --- a/route_test.go +++ b/route_test.go @@ -216,6 +216,67 @@ func TestRouteReplace(t *testing.T) { } +func TestRouteChange(t *testing.T) { + tearDown := setUpNetlinkTest(t) + defer tearDown() + + // get loopback interface + link, err := LinkByName("lo") + if err != nil { + t.Fatal(err) + } + + // bring the interface up + if err := LinkSetUp(link); err != nil { + t.Fatal(err) + } + + // add a gateway route + dst := &net.IPNet{ + IP: net.IPv4(192, 168, 0, 0), + Mask: net.CIDRMask(24, 32), + } + + ip := net.IPv4(127, 1, 1, 1) + route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip} + if err := RouteAdd(&route); err != nil { + t.Fatal(err) + } + routes, err := RouteList(link, FAMILY_V4) + if err != nil { + t.Fatal(err) + } + if len(routes) != 1 { + t.Fatal("Route not added properly") + } + + ip = net.IPv4(127, 1, 1, 2) + route = Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip} + if err := RouteChange(&route); err != nil { + t.Fatal(err) + } + + routes, err = RouteList(link, FAMILY_V4) + if err != nil { + t.Fatal(err) + } + + if len(routes) != 1 || !routes[0].Src.Equal(ip) { + t.Fatal("Route not replaced properly") + } + + if err := RouteDel(&route); err != nil { + t.Fatal(err) + } + routes, err = RouteList(link, FAMILY_V4) + if err != nil { + t.Fatal(err) + } + if len(routes) != 0 { + t.Fatal("Route not removed properly") + } +} + func TestRouteAppend(t *testing.T) { tearDown := setUpNetlinkTest(t) defer tearDown()