| package netlink |
| |
| import ( |
| "fmt" |
| "net" |
| "strings" |
| "syscall" |
| |
| "github.com/vishvananda/netlink/nl" |
| ) |
| |
| type PDP struct { |
| Version uint32 |
| TID uint64 |
| PeerAddress net.IP |
| MSAddress net.IP |
| Flow uint16 |
| NetNSFD uint32 |
| ITEI uint32 |
| OTEI uint32 |
| } |
| |
| func (pdp *PDP) String() string { |
| elems := []string{} |
| elems = append(elems, fmt.Sprintf("Version: %d", pdp.Version)) |
| if pdp.Version == 0 { |
| elems = append(elems, fmt.Sprintf("TID: %d", pdp.TID)) |
| } else if pdp.Version == 1 { |
| elems = append(elems, fmt.Sprintf("TEI: %d/%d", pdp.ITEI, pdp.OTEI)) |
| } |
| elems = append(elems, fmt.Sprintf("MS-Address: %s", pdp.MSAddress)) |
| elems = append(elems, fmt.Sprintf("Peer-Address: %s", pdp.PeerAddress)) |
| return fmt.Sprintf("{%s}", strings.Join(elems, " ")) |
| } |
| |
| func (p *PDP) parseAttributes(attrs []syscall.NetlinkRouteAttr) error { |
| for _, a := range attrs { |
| switch a.Attr.Type { |
| case nl.GENL_GTP_ATTR_VERSION: |
| p.Version = native.Uint32(a.Value) |
| case nl.GENL_GTP_ATTR_TID: |
| p.TID = native.Uint64(a.Value) |
| case nl.GENL_GTP_ATTR_PEER_ADDRESS: |
| p.PeerAddress = net.IP(a.Value) |
| case nl.GENL_GTP_ATTR_MS_ADDRESS: |
| p.MSAddress = net.IP(a.Value) |
| case nl.GENL_GTP_ATTR_FLOW: |
| p.Flow = native.Uint16(a.Value) |
| case nl.GENL_GTP_ATTR_NET_NS_FD: |
| p.NetNSFD = native.Uint32(a.Value) |
| case nl.GENL_GTP_ATTR_I_TEI: |
| p.ITEI = native.Uint32(a.Value) |
| case nl.GENL_GTP_ATTR_O_TEI: |
| p.OTEI = native.Uint32(a.Value) |
| } |
| } |
| return nil |
| } |
| |
| func parsePDP(msgs [][]byte) ([]*PDP, error) { |
| pdps := make([]*PDP, 0, len(msgs)) |
| for _, m := range msgs { |
| attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:]) |
| if err != nil { |
| return nil, err |
| } |
| pdp := &PDP{} |
| if err := pdp.parseAttributes(attrs); err != nil { |
| return nil, err |
| } |
| pdps = append(pdps, pdp) |
| } |
| return pdps, nil |
| } |
| |
| func (h *Handle) GTPPDPList() ([]*PDP, error) { |
| f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) |
| if err != nil { |
| return nil, err |
| } |
| msg := &nl.Genlmsg{ |
| Command: nl.GENL_GTP_CMD_GETPDP, |
| Version: nl.GENL_GTP_VERSION, |
| } |
| req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_DUMP) |
| req.AddData(msg) |
| msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0) |
| if err != nil { |
| return nil, err |
| } |
| return parsePDP(msgs) |
| } |
| |
| func GTPPDPList() ([]*PDP, error) { |
| return pkgHandle.GTPPDPList() |
| } |
| |
| func gtpPDPGet(req *nl.NetlinkRequest) (*PDP, error) { |
| msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0) |
| if err != nil { |
| return nil, err |
| } |
| pdps, err := parsePDP(msgs) |
| if err != nil { |
| return nil, err |
| } |
| if len(pdps) != 1 { |
| return nil, fmt.Errorf("invalid reqponse for GENL_GTP_CMD_GETPDP") |
| } |
| return pdps[0], nil |
| } |
| |
| func (h *Handle) GTPPDPByTID(link Link, tid int) (*PDP, error) { |
| f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) |
| if err != nil { |
| return nil, err |
| } |
| msg := &nl.Genlmsg{ |
| Command: nl.GENL_GTP_CMD_GETPDP, |
| Version: nl.GENL_GTP_VERSION, |
| } |
| req := h.newNetlinkRequest(int(f.ID), 0) |
| req.AddData(msg) |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(0))) |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(uint64(tid)))) |
| return gtpPDPGet(req) |
| } |
| |
| func GTPPDPByTID(link Link, tid int) (*PDP, error) { |
| return pkgHandle.GTPPDPByTID(link, tid) |
| } |
| |
| func (h *Handle) GTPPDPByITEI(link Link, itei int) (*PDP, error) { |
| f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) |
| if err != nil { |
| return nil, err |
| } |
| msg := &nl.Genlmsg{ |
| Command: nl.GENL_GTP_CMD_GETPDP, |
| Version: nl.GENL_GTP_VERSION, |
| } |
| req := h.newNetlinkRequest(int(f.ID), 0) |
| req.AddData(msg) |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(1))) |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(uint32(itei)))) |
| return gtpPDPGet(req) |
| } |
| |
| func GTPPDPByITEI(link Link, itei int) (*PDP, error) { |
| return pkgHandle.GTPPDPByITEI(link, itei) |
| } |
| |
| func (h *Handle) GTPPDPByMSAddress(link Link, addr net.IP) (*PDP, error) { |
| f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) |
| if err != nil { |
| return nil, err |
| } |
| msg := &nl.Genlmsg{ |
| Command: nl.GENL_GTP_CMD_GETPDP, |
| Version: nl.GENL_GTP_VERSION, |
| } |
| req := h.newNetlinkRequest(int(f.ID), 0) |
| req.AddData(msg) |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(0))) |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_MS_ADDRESS, []byte(addr.To4()))) |
| return gtpPDPGet(req) |
| } |
| |
| func GTPPDPByMSAddress(link Link, addr net.IP) (*PDP, error) { |
| return pkgHandle.GTPPDPByMSAddress(link, addr) |
| } |
| |
| func (h *Handle) GTPPDPAdd(link Link, pdp *PDP) error { |
| f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) |
| if err != nil { |
| return err |
| } |
| msg := &nl.Genlmsg{ |
| Command: nl.GENL_GTP_CMD_NEWPDP, |
| Version: nl.GENL_GTP_VERSION, |
| } |
| req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_EXCL|syscall.NLM_F_ACK) |
| req.AddData(msg) |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version))) |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_PEER_ADDRESS, []byte(pdp.PeerAddress.To4()))) |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_MS_ADDRESS, []byte(pdp.MSAddress.To4()))) |
| |
| switch pdp.Version { |
| case 0: |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(pdp.TID))) |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_FLOW, nl.Uint16Attr(pdp.Flow))) |
| case 1: |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(pdp.ITEI))) |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_O_TEI, nl.Uint32Attr(pdp.OTEI))) |
| default: |
| return fmt.Errorf("unsupported GTP version: %d", pdp.Version) |
| } |
| _, err = req.Execute(syscall.NETLINK_GENERIC, 0) |
| return err |
| } |
| |
| func GTPPDPAdd(link Link, pdp *PDP) error { |
| return pkgHandle.GTPPDPAdd(link, pdp) |
| } |
| |
| func (h *Handle) GTPPDPDel(link Link, pdp *PDP) error { |
| f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) |
| if err != nil { |
| return err |
| } |
| msg := &nl.Genlmsg{ |
| Command: nl.GENL_GTP_CMD_DELPDP, |
| Version: nl.GENL_GTP_VERSION, |
| } |
| req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_EXCL|syscall.NLM_F_ACK) |
| req.AddData(msg) |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version))) |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) |
| |
| switch pdp.Version { |
| case 0: |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(pdp.TID))) |
| case 1: |
| req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(pdp.ITEI))) |
| default: |
| return fmt.Errorf("unsupported GTP version: %d", pdp.Version) |
| } |
| _, err = req.Execute(syscall.NETLINK_GENERIC, 0) |
| return err |
| } |
| |
| func GTPPDPDel(link Link, pdp *PDP) error { |
| return pkgHandle.GTPPDPDel(link, pdp) |
| } |