1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
//go:build linux
package network
import (
"fmt"
"net"
"strings"
"github.com/vishvananda/netlink"
)
// InterfaceInfo contains basic information about a network interface.
type InterfaceInfo struct {
Name string
Index int
}
// NetworkOps abstracts the low-level netlink operations.
type NetworkOps interface {
LinkList() ([]netlink.Link, error)
LinkByName(name string) (netlink.Link, error)
LinkSetMTU(link netlink.Link, mtu int) error
LinkSetUp(link netlink.Link) error
AddrAdd(link netlink.Link, addr *netlink.Addr) error
RouteAdd(route *netlink.Route) error
RouteReplace(route *netlink.Route) error
}
// realNetworkOps is the production implementation using netlink.
type realNetworkOps struct{}
func (r *realNetworkOps) LinkList() ([]netlink.Link, error) { return netlink.LinkList() }
func (r *realNetworkOps) LinkByName(name string) (netlink.Link, error) {
return netlink.LinkByName(name)
}
func (r *realNetworkOps) LinkSetMTU(link netlink.Link, mtu int) error {
return netlink.LinkSetMTU(link, mtu)
}
func (r *realNetworkOps) LinkSetUp(link netlink.Link) error { return netlink.LinkSetUp(link) }
func (r *realNetworkOps) AddrAdd(link netlink.Link, addr *netlink.Addr) error {
return netlink.AddrAdd(link, addr)
}
func (r *realNetworkOps) RouteAdd(route *netlink.Route) error { return netlink.RouteAdd(route) }
func (r *realNetworkOps) RouteReplace(route *netlink.Route) error { return netlink.RouteReplace(route) }
// DefaultNetworkOps is the global instance used by the package functions.
// It can be replaced during tests.
var DefaultNetworkOps NetworkOps = &realNetworkOps{}
// NetworkManager coordinates network configuration within a namespace.
type NetworkManager struct {
Ops NetworkOps
}
// NewNetworkManager creates a new NetworkManager with production defaults.
func NewNetworkManager() *NetworkManager {
return &NetworkManager{
Ops: DefaultNetworkOps,
}
}
// ListInterfaces returns a list of all network interfaces present in the current namespace.
func (nm *NetworkManager) ListInterfaces() ([]InterfaceInfo, error) {
links, err := nm.Ops.LinkList()
if err != nil {
return nil, fmt.Errorf("failed to list interfaces: %w", err)
}
var interfaces []InterfaceInfo
for _, link := range links {
interfaces = append(interfaces, InterfaceInfo{
Name: link.Attrs().Name,
Index: link.Attrs().Index,
})
}
return interfaces, nil
}
// ConfigureInterface sets the MTU, brings the interface up, assigns an IP address,
// and configures the default route.
func (nm *NetworkManager) ConfigureInterface(name, address string, mtu int) error {
link, err := nm.Ops.LinkByName(name)
if err != nil {
return fmt.Errorf("failed to find link %s: %w", name, err)
}
if err := nm.Ops.LinkSetMTU(link, mtu); err != nil {
return fmt.Errorf("failed to set MTU %d on link %s: %w", mtu, name, err)
}
if err := nm.Ops.LinkSetUp(link); err != nil {
return fmt.Errorf("failed to bring up link %s: %w", name, err)
}
addr, err := netlink.ParseAddr(address)
if err != nil {
return fmt.Errorf("invalid IP address %s: %w", address, err)
}
if err := nm.Ops.AddrAdd(link, addr); err != nil {
if !strings.Contains(err.Error(), "file exists") {
return fmt.Errorf("failed to add address %s to link %s: %w", address, name, err)
}
}
var dst *net.IPNet
if addr.IP.To4() != nil {
_, dst, _ = net.ParseCIDR("0.0.0.0/0")
} else {
_, dst, _ = net.ParseCIDR("::/0")
}
route := &netlink.Route{
Scope: netlink.SCOPE_UNIVERSE,
LinkIndex: link.Attrs().Index,
Dst: dst,
}
if err := nm.Ops.RouteAdd(route); err != nil {
if err := nm.Ops.RouteReplace(route); err != nil {
return fmt.Errorf("failed to configure default route via %s: %w", name, err)
}
}
return nil
}
// ListInterfaces returns a list of all network interfaces present in the current namespace.
func ListInterfaces() ([]InterfaceInfo, error) {
return NewNetworkManager().ListInterfaces()
}
// ConfigureInterface sets the MTU, brings the interface up, assigns an IP address,
// and configures the default route.
func ConfigureInterface(name, address string, mtu int) error {
return NewNetworkManager().ConfigureInterface(name, address, mtu)
}
|