github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/libnetwork/drivers/macvlan/macvlan_setup.go (about) 1 package macvlan 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 8 "github.com/Sirupsen/logrus" 9 "github.com/docker/libnetwork/ns" 10 "github.com/vishvananda/netlink" 11 ) 12 13 const ( 14 dummyPrefix = "dm-" // macvlan prefix for dummy parent interface 15 macvlanKernelVer = 3 // minimum macvlan kernel support 16 macvlanMajorVer = 9 // minimum macvlan major kernel support 17 ) 18 19 // Create the macvlan slave specifying the source name 20 func createMacVlan(containerIfName, parent, macvlanMode string) (string, error) { 21 // Set the macvlan mode. Default is bridge mode 22 mode, err := setMacVlanMode(macvlanMode) 23 if err != nil { 24 return "", fmt.Errorf("Unsupported %s macvlan mode: %v", macvlanMode, err) 25 } 26 // verify the Docker host interface acting as the macvlan parent iface exists 27 if !parentExists(parent) { 28 return "", fmt.Errorf("the requested parent interface %s was not found on the Docker host", parent) 29 } 30 // Get the link for the master index (Example: the docker host eth iface) 31 parentLink, err := ns.NlHandle().LinkByName(parent) 32 if err != nil { 33 return "", fmt.Errorf("error occoured looking up the %s parent iface %s error: %s", macvlanType, parent, err) 34 } 35 // Create a macvlan link 36 macvlan := &netlink.Macvlan{ 37 LinkAttrs: netlink.LinkAttrs{ 38 Name: containerIfName, 39 ParentIndex: parentLink.Attrs().Index, 40 }, 41 Mode: mode, 42 } 43 if err := ns.NlHandle().LinkAdd(macvlan); err != nil { 44 // If a user creates a macvlan and ipvlan on same parent, only one slave iface can be active at a time. 45 return "", fmt.Errorf("failed to create the %s port: %v", macvlanType, err) 46 } 47 48 return macvlan.Attrs().Name, nil 49 } 50 51 // setMacVlanMode setter for one of the four macvlan port types 52 func setMacVlanMode(mode string) (netlink.MacvlanMode, error) { 53 switch mode { 54 case modePrivate: 55 return netlink.MACVLAN_MODE_PRIVATE, nil 56 case modeVepa: 57 return netlink.MACVLAN_MODE_VEPA, nil 58 case modeBridge: 59 return netlink.MACVLAN_MODE_BRIDGE, nil 60 case modePassthru: 61 return netlink.MACVLAN_MODE_PASSTHRU, nil 62 default: 63 return 0, fmt.Errorf("unknown macvlan mode: %s", mode) 64 } 65 } 66 67 // parentExists check if the specified interface exists in the default namespace 68 func parentExists(ifaceStr string) bool { 69 _, err := ns.NlHandle().LinkByName(ifaceStr) 70 if err != nil { 71 return false 72 } 73 74 return true 75 } 76 77 // createVlanLink parses sub-interfaces and vlan id for creation 78 func createVlanLink(parentName string) error { 79 if strings.Contains(parentName, ".") { 80 parent, vidInt, err := parseVlan(parentName) 81 if err != nil { 82 return err 83 } 84 // VLAN identifier or VID is a 12-bit field specifying the VLAN to which the frame belongs 85 if vidInt > 4094 || vidInt < 1 { 86 return fmt.Errorf("vlan id must be between 1-4094, received: %d", vidInt) 87 } 88 // get the parent link to attach a vlan subinterface 89 parentLink, err := ns.NlHandle().LinkByName(parent) 90 if err != nil { 91 return fmt.Errorf("failed to find master interface %s on the Docker host: %v", parent, err) 92 } 93 vlanLink := &netlink.Vlan{ 94 LinkAttrs: netlink.LinkAttrs{ 95 Name: parentName, 96 ParentIndex: parentLink.Attrs().Index, 97 }, 98 VlanId: vidInt, 99 } 100 // create the subinterface 101 if err := ns.NlHandle().LinkAdd(vlanLink); err != nil { 102 return fmt.Errorf("failed to create %s vlan link: %v", vlanLink.Name, err) 103 } 104 // Bring the new netlink iface up 105 if err := ns.NlHandle().LinkSetUp(vlanLink); err != nil { 106 return fmt.Errorf("failed to enable %s the macvlan parent link %v", vlanLink.Name, err) 107 } 108 logrus.Debugf("Added a vlan tagged netlink subinterface: %s with a vlan id: %d", parentName, vidInt) 109 return nil 110 } 111 112 return fmt.Errorf("invalid subinterface vlan name %s, example formatting is eth0.10", parentName) 113 } 114 115 // delVlanLink verifies only sub-interfaces with a vlan id get deleted 116 func delVlanLink(linkName string) error { 117 if strings.Contains(linkName, ".") { 118 _, _, err := parseVlan(linkName) 119 if err != nil { 120 return err 121 } 122 // delete the vlan subinterface 123 vlanLink, err := ns.NlHandle().LinkByName(linkName) 124 if err != nil { 125 return fmt.Errorf("failed to find interface %s on the Docker host : %v", linkName, err) 126 } 127 // verify a parent interface isn't being deleted 128 if vlanLink.Attrs().ParentIndex == 0 { 129 return fmt.Errorf("interface %s does not appear to be a slave device: %v", linkName, err) 130 } 131 // delete the macvlan slave device 132 if err := ns.NlHandle().LinkDel(vlanLink); err != nil { 133 return fmt.Errorf("failed to delete %s link: %v", linkName, err) 134 } 135 logrus.Debugf("Deleted a vlan tagged netlink subinterface: %s", linkName) 136 } 137 // if the subinterface doesn't parse to iface.vlan_id leave the interface in 138 // place since it could be a user specified name not created by the driver. 139 return nil 140 } 141 142 // parseVlan parses and verifies a slave interface name: -o parent=eth0.10 143 func parseVlan(linkName string) (string, int, error) { 144 // parse -o parent=eth0.10 145 splitName := strings.Split(linkName, ".") 146 if len(splitName) != 2 { 147 return "", 0, fmt.Errorf("required interface name format is: name.vlan_id, ex. eth0.10 for vlan 10, instead received %s", linkName) 148 } 149 parent, vidStr := splitName[0], splitName[1] 150 // validate type and convert vlan id to int 151 vidInt, err := strconv.Atoi(vidStr) 152 if err != nil { 153 return "", 0, fmt.Errorf("unable to parse a valid vlan id from: %s (ex. eth0.10 for vlan 10)", vidStr) 154 } 155 // Check if the interface exists 156 if !parentExists(parent) { 157 return "", 0, fmt.Errorf("-o parent interface does was not found on the host: %s", parent) 158 } 159 160 return parent, vidInt, nil 161 } 162 163 // createDummyLink creates a dummy0 parent link 164 func createDummyLink(dummyName, truncNetID string) error { 165 // create a parent interface since one was not specified 166 parent := &netlink.Dummy{ 167 LinkAttrs: netlink.LinkAttrs{ 168 Name: dummyName, 169 }, 170 } 171 if err := ns.NlHandle().LinkAdd(parent); err != nil { 172 return err 173 } 174 parentDummyLink, err := ns.NlHandle().LinkByName(dummyName) 175 if err != nil { 176 return fmt.Errorf("error occoured looking up the %s parent iface %s error: %s", macvlanType, dummyName, err) 177 } 178 // bring the new netlink iface up 179 if err := ns.NlHandle().LinkSetUp(parentDummyLink); err != nil { 180 return fmt.Errorf("failed to enable %s the macvlan parent link: %v", dummyName, err) 181 } 182 183 return nil 184 } 185 186 // delDummyLink deletes the link type dummy used when -o parent is not passed 187 func delDummyLink(linkName string) error { 188 // delete the vlan subinterface 189 dummyLink, err := ns.NlHandle().LinkByName(linkName) 190 if err != nil { 191 return fmt.Errorf("failed to find link %s on the Docker host : %v", linkName, err) 192 } 193 // verify a parent interface is being deleted 194 if dummyLink.Attrs().ParentIndex != 0 { 195 return fmt.Errorf("link %s is not a parent dummy interface", linkName) 196 } 197 // delete the macvlan dummy device 198 if err := ns.NlHandle().LinkDel(dummyLink); err != nil { 199 return fmt.Errorf("failed to delete the dummy %s link: %v", linkName, err) 200 } 201 logrus.Debugf("Deleted a dummy parent link: %s", linkName) 202 203 return nil 204 } 205 206 // getDummyName returns the name of a dummy parent with truncated net ID and driver prefix 207 func getDummyName(netID string) string { 208 return fmt.Sprintf("%s%s", dummyPrefix, netID) 209 }