diff --git a/handle_unspecified.go b/handle_unspecified.go index d096668..3fe0364 100644 --- a/handle_unspecified.go +++ b/handle_unspecified.go @@ -263,6 +263,10 @@ func (h *Handle) RouteAppend(route *Route) error { return ErrNotImplemented } +func (h *Handle) RouteChange(route *Route) error { + return ErrNotImplemented +} + func (h *Handle) RouteDel(route *Route) error { return ErrNotImplemented } diff --git a/netlink_unspecified.go b/netlink_unspecified.go index adac048..0f6fde2 100644 --- a/netlink_unspecified.go +++ b/netlink_unspecified.go @@ -204,6 +204,10 @@ func RouteAppend(route *Route) error { return ErrNotImplemented } +func RouteChange(route *Route) error { + return ErrNotImplemented +} + func RouteDel(route *Route) error { return ErrNotImplemented } diff --git a/route_linux.go b/route_linux.go index 99467df..30a1d69 100644 --- a/route_linux.go +++ b/route_linux.go @@ -790,6 +790,21 @@ func (h *Handle) RouteAddEcmp(route *Route) error { return err } +// RouteChange will change an existing route in the system. +// Equivalent to: `ip route change $route` +func RouteChange(route *Route) error { + return pkgHandle.RouteChange(route) +} + +// RouteChange will change an existing route in 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 +} + // RouteReplace will add a route to the system. // Equivalent to: `ip route replace $route` func RouteReplace(route *Route) error { diff --git a/route_test.go b/route_test.go index a862bbb..67497e2 100644 --- a/route_test.go +++ b/route_test.go @@ -331,6 +331,72 @@ func TestRoute6AddDel(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 := RouteChange(&route); err == nil { + t.Fatal("Route added while it should fail") + } + + 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 changed 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 TestRouteReplace(t *testing.T) { tearDown := setUpNetlinkTest(t) defer tearDown() @@ -390,7 +456,6 @@ func TestRouteReplace(t *testing.T) { if len(routes) != 0 { t.Fatal("Route not removed properly") } - } func TestRouteAppend(t *testing.T) {