1package overlay
2
3import (
4	"fmt"
5	"strings"
6	"syscall"
7
8	"github.com/sirupsen/logrus"
9	"github.com/docker/libnetwork/netutils"
10	"github.com/docker/libnetwork/ns"
11	"github.com/docker/libnetwork/osl"
12	"github.com/vishvananda/netlink"
13	"github.com/vishvananda/netns"
14)
15
16var soTimeout = ns.NetlinkSocketsTimeout
17
18func validateID(nid, eid string) error {
19	if nid == "" {
20		return fmt.Errorf("invalid network id")
21	}
22
23	if eid == "" {
24		return fmt.Errorf("invalid endpoint id")
25	}
26
27	return nil
28}
29
30func createVethPair() (string, string, error) {
31	defer osl.InitOSContext()()
32	nlh := ns.NlHandle()
33
34	// Generate a name for what will be the host side pipe interface
35	name1, err := netutils.GenerateIfaceName(nlh, vethPrefix, vethLen)
36	if err != nil {
37		return "", "", fmt.Errorf("error generating veth name1: %v", err)
38	}
39
40	// Generate a name for what will be the sandbox side pipe interface
41	name2, err := netutils.GenerateIfaceName(nlh, vethPrefix, vethLen)
42	if err != nil {
43		return "", "", fmt.Errorf("error generating veth name2: %v", err)
44	}
45
46	// Generate and add the interface pipe host <-> sandbox
47	veth := &netlink.Veth{
48		LinkAttrs: netlink.LinkAttrs{Name: name1, TxQLen: 0},
49		PeerName:  name2}
50	if err := nlh.LinkAdd(veth); err != nil {
51		return "", "", fmt.Errorf("error creating veth pair: %v", err)
52	}
53
54	return name1, name2, nil
55}
56
57func createVxlan(name string, vni uint32, mtu int) error {
58	defer osl.InitOSContext()()
59
60	vxlan := &netlink.Vxlan{
61		LinkAttrs: netlink.LinkAttrs{Name: name, MTU: mtu},
62		VxlanId:   int(vni),
63		Learning:  true,
64		Port:      vxlanPort,
65		Proxy:     true,
66		L3miss:    true,
67		L2miss:    true,
68	}
69
70	if err := ns.NlHandle().LinkAdd(vxlan); err != nil {
71		return fmt.Errorf("error creating vxlan interface: %v", err)
72	}
73
74	return nil
75}
76
77func deleteInterfaceBySubnet(brPrefix string, s *subnet) error {
78	defer osl.InitOSContext()()
79
80	nlh := ns.NlHandle()
81	links, err := nlh.LinkList()
82	if err != nil {
83		return fmt.Errorf("failed to list interfaces while deleting bridge interface by subnet: %v", err)
84	}
85
86	for _, l := range links {
87		name := l.Attrs().Name
88		if _, ok := l.(*netlink.Bridge); ok && strings.HasPrefix(name, brPrefix) {
89			addrList, err := nlh.AddrList(l, netlink.FAMILY_V4)
90			if err != nil {
91				logrus.Errorf("error getting AddressList for bridge %s", name)
92				continue
93			}
94			for _, addr := range addrList {
95				if netutils.NetworkOverlaps(addr.IPNet, s.subnetIP) {
96					err = nlh.LinkDel(l)
97					if err != nil {
98						logrus.Errorf("error deleting bridge (%s) with subnet %v: %v", name, addr.IPNet, err)
99					}
100				}
101			}
102		}
103	}
104	return nil
105
106}
107
108func deleteInterface(name string) error {
109	defer osl.InitOSContext()()
110
111	link, err := ns.NlHandle().LinkByName(name)
112	if err != nil {
113		return fmt.Errorf("failed to find interface with name %s: %v", name, err)
114	}
115
116	if err := ns.NlHandle().LinkDel(link); err != nil {
117		return fmt.Errorf("error deleting interface with name %s: %v", name, err)
118	}
119
120	return nil
121}
122
123func deleteVxlanByVNI(path string, vni uint32) error {
124	defer osl.InitOSContext()()
125
126	nlh := ns.NlHandle()
127	if path != "" {
128		ns, err := netns.GetFromPath(path)
129		if err != nil {
130			return fmt.Errorf("failed to get ns handle for %s: %v", path, err)
131		}
132		defer ns.Close()
133
134		nlh, err = netlink.NewHandleAt(ns, syscall.NETLINK_ROUTE)
135		if err != nil {
136			return fmt.Errorf("failed to get netlink handle for ns %s: %v", path, err)
137		}
138		defer nlh.Delete()
139		err = nlh.SetSocketTimeout(soTimeout)
140		if err != nil {
141			logrus.Warnf("Failed to set the timeout on the netlink handle sockets for vxlan deletion: %v", err)
142		}
143	}
144
145	links, err := nlh.LinkList()
146	if err != nil {
147		return fmt.Errorf("failed to list interfaces while deleting vxlan interface by vni: %v", err)
148	}
149
150	for _, l := range links {
151		if l.Type() == "vxlan" && (vni == 0 || l.(*netlink.Vxlan).VxlanId == int(vni)) {
152			err = nlh.LinkDel(l)
153			if err != nil {
154				return fmt.Errorf("error deleting vxlan interface with id %d: %v", vni, err)
155			}
156			return nil
157		}
158	}
159
160	return fmt.Errorf("could not find a vxlan interface to delete with id %d", vni)
161}
162