// Pack Service to a set of nlattrs. // If full is given, include service settings, otherwise only the identifying fields are given. func (self *Service) attrs(full bool) nlgo.AttrSlice { var attrs nlgo.AttrSlice if self.FwMark != 0 { attrs = append(attrs, nlattr(IPVS_SVC_ATTR_AF, nlgo.U16(self.Af)), nlattr(IPVS_SVC_ATTR_FWMARK, nlgo.U32(self.FwMark)), ) } else if self.Protocol != 0 && self.Addr != nil && self.Port != 0 { attrs = append(attrs, nlattr(IPVS_SVC_ATTR_AF, nlgo.U16(self.Af)), nlattr(IPVS_SVC_ATTR_PROTOCOL, nlgo.U16(self.Protocol)), nlattr(IPVS_SVC_ATTR_ADDR, packAddr(self.Af, self.Addr)), nlattr(IPVS_SVC_ATTR_PORT, packPort(self.Port)), ) } else { panic("Incomplete service id fields") } if full { attrs = append(attrs, nlattr(IPVS_SVC_ATTR_SCHED_NAME, nlgo.NulString(self.SchedName)), nlattr(IPVS_SVC_ATTR_FLAGS, pack(&self.Flags)), nlattr(IPVS_SVC_ATTR_TIMEOUT, nlgo.U32(self.Timeout)), nlattr(IPVS_SVC_ATTR_NETMASK, nlgo.U32(self.Netmask)), ) } return attrs }
func TestInfo(t *testing.T) { testAttrs := nlgo.AttrMap{Policy: ipvs_info_policy, AttrSlice: nlgo.AttrSlice{ {Header: syscall.NlAttr{Type: IPVS_INFO_ATTR_VERSION}, Value: nlgo.U32(0x00010203)}, {Header: syscall.NlAttr{Type: IPVS_INFO_ATTR_CONN_TAB_SIZE}, Value: nlgo.U32(4096)}, }} if info, err := unpackInfo(testAttrs); err != nil { t.Errorf("error Info.unpack(): %s", err) } else { if info.Version.String() != "1.2.3" { t.Errorf("fail Info.Version: %s != 1.2.3", info.Version.String()) } if info.ConnTabSize != 4096 { t.Errorf("fail Info.ConnTabSize: %s != 4096", info.ConnTabSize) } } }
// Dump Dest as nl attrs, using the Af of the corresponding Service. // If full, includes Dest setting attrs, otherwise only identifying attrs. func (self *Dest) attrs(service *Service, full bool) nlgo.AttrSlice { var attrs nlgo.AttrSlice attrs = append(attrs, nlattr(IPVS_DEST_ATTR_ADDR, packAddr(service.Af, self.Addr)), nlattr(IPVS_DEST_ATTR_PORT, packPort(self.Port)), ) if full { attrs = append(attrs, nlattr(IPVS_DEST_ATTR_FWD_METHOD, nlgo.U32(self.FwdMethod)), nlattr(IPVS_DEST_ATTR_WEIGHT, nlgo.U32(self.Weight)), nlattr(IPVS_DEST_ATTR_U_THRESH, nlgo.U32(self.UThresh)), nlattr(IPVS_DEST_ATTR_L_THRESH, nlgo.U32(self.LThresh)), ) } return attrs }
func TestDest(t *testing.T) { testService := Service{ Af: syscall.AF_INET6, } testDest := Dest{ Addr: net.ParseIP("2001:db8:6b:6b::0"), Port: 1337, FwdMethod: IP_VS_CONN_F_TUNNEL, Weight: 10, UThresh: 1000, LThresh: 0, } testAttrs := nlgo.AttrSlice{ nlattr(IPVS_DEST_ATTR_ADDR, nlgo.Binary([]byte{0x20, 0x01, 0x0d, 0xb8, 0x00, 0x6b, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), nlattr(IPVS_DEST_ATTR_PORT, nlgo.U16(0x3905)), nlattr(IPVS_DEST_ATTR_FWD_METHOD, nlgo.U32(IP_VS_CONN_F_TUNNEL)), nlattr(IPVS_DEST_ATTR_WEIGHT, nlgo.U32(10)), nlattr(IPVS_DEST_ATTR_U_THRESH, nlgo.U32(1000)), nlattr(IPVS_DEST_ATTR_L_THRESH, nlgo.U32(0)), } // pack packAttrs := testDest.attrs(&testService, true) packBytes := packAttrs.Bytes() if !bytes.Equal(packBytes, testAttrs.Bytes()) { t.Errorf("fail Dest.attrs(): \n%s", hex.Dump(packBytes)) } // unpack if unpackedAttrs, err := ipvs_dest_policy.Parse(packBytes); err != nil { t.Fatalf("error ipvs_dest_policy.Parse: %s", err) } else if unpackedDest, err := unpackDest(testService, unpackedAttrs.(nlgo.AttrMap)); err != nil { t.Fatalf("error unpackDest: %s", err) } else { testDestEquals(t, testDest, unpackedDest) } }
func (self *NamedPortManager) RtListen(ev nlgo.RtMessage) { mtype := ev.Message.Header.Type if mtype != syscall.RTM_NEWLINK && mtype != syscall.RTM_DELLINK { return // no concern } ifinfo := (*syscall.IfInfomsg)(unsafe.Pointer(&ev.Message.Data[0])) evPort := &NamedPort{ ifIndex: uint32(ifinfo.Index), flags: ifinfo.Flags, fd: -1, lock: &sync.Mutex{}, rhub: self.rhub, } if attrs, err := nlgo.RouteLinkPolicy.Parse(ev.Message.Data[nlgo.NLMSG_ALIGN(syscall.SizeofIfInfomsg):]); err != nil { log.Print(err) } else if amap, ok := attrs.(nlgo.AttrMap); !ok { log.Print("route link policy did not return attr map") } else { if t := amap.Get(nlgo.IFLA_IFNAME); t != nil { evPort.name = string(t.(nlgo.NulString)) } if t := amap.Get(nlgo.IFLA_MTU); t != nil { evPort.mtu = uint32(t.(nlgo.U32)) } if t := amap.Get(nlgo.IFLA_ADDRESS); t != nil { evPort.mac = []byte(t.(nlgo.Binary)) } } switch mtype { case syscall.RTM_NEWLINK: if port := self.ports[evPort.ifIndex]; port != nil { port.flags = ifinfo.Flags if len(evPort.name) > 0 { port.name = evPort.name } if evPort.mtu != 0 { port.mtu = evPort.mtu } if len(evPort.mac) != 0 { port.mac = evPort.mac } port.monitor <- true if err := port.Up(); err != nil { // maybe ready for up log.Print(err) } return } // query wiphy if res, err := self.ghub.Request("nl80211", 1, nlgo.NL80211_CMD_GET_INTERFACE, syscall.NLM_F_DUMP, nil, nlgo.AttrSlice{ nlgo.Attr{ Header: syscall.NlAttr{ Type: nlgo.NL80211_ATTR_IFINDEX, }, Value: nlgo.U32(ifinfo.Index), }, }); err != nil { log.Print(err) } else { for _, r := range res { if r.Error != nil { log.Print(r.Error) } if r.Family != "nl80211" { continue } if attrs, err := nlgo.Nl80211Policy.Parse(r.Payload); err != nil { log.Print(err) } else if amap, ok := attrs.(nlgo.AttrMap); !ok { log.Print("nl80211 attr policy error") } else { if evPort.ifIndex == uint32(amap.Get(nlgo.NL80211_ATTR_IFINDEX).(nlgo.U32)) { evPort.hasWiphy = true evPort.wiphy = uint32(amap.Get(nlgo.NL80211_ATTR_WIPHY).(nlgo.U32)) } } } } tracking := func(port *NamedPort) bool { for _, name := range self.trackingNames { if port.name == name { return true } } if port.hasWiphy { for _, wiphy := range self.trackingWiphy { if port.wiphy == wiphy { return true } } } for idx, _ := range self.ports { if idx == port.ifIndex { return true } } return false } if tracking(evPort) { port := evPort port.ingress = make(chan Frame) port.monitor = make(chan bool) self.ports[uint32(ifinfo.Index)] = port func() { if port.hasWiphy { for _, wiphy := range self.trackingWiphy { if wiphy == port.wiphy { return } } self.trackingWiphy = append(self.trackingWiphy, port.wiphy) } }() self.datapath.AddPort(port) port.monitor <- true if err := port.Up(); err != nil { // maybe ready for up log.Print(err) } } case syscall.RTM_DELLINK: if port, ok := self.ports[evPort.ifIndex]; ok && port != nil { port.Down() port.Close() delete(self.ports, evPort.ifIndex) } // for wiphy unplug if res, err := self.ghub.Request("nl80211", 1, nlgo.NL80211_CMD_GET_WIPHY, syscall.NLM_F_DUMP, nil, nil); err != nil { log.Print(err) } else { var activeWiphy []uint32 for _, r := range res { if r.Family != "nl80211" { continue } if attrs, err := nlgo.Nl80211Policy.Parse(r.Payload); err != nil { log.Print(err) } else { activeWiphy = append(activeWiphy, uint32(attrs.(nlgo.AttrMap).Get(nlgo.NL80211_ATTR_WIPHY).(nlgo.U32))) } } var trackingWiphy []uint32 for _, wiphy := range self.trackingWiphy { for _, active := range activeWiphy { if wiphy == active { trackingWiphy = append(trackingWiphy, wiphy) } } } self.trackingWiphy = trackingWiphy } } }