1package netlink 2 3import ( 4 "fmt" 5 "net" 6 "strings" 7 "syscall" 8 9 "github.com/vishvananda/netlink/nl" 10) 11 12type PDP struct { 13 Version uint32 14 TID uint64 15 PeerAddress net.IP 16 MSAddress net.IP 17 Flow uint16 18 NetNSFD uint32 19 ITEI uint32 20 OTEI uint32 21} 22 23func (pdp *PDP) String() string { 24 elems := []string{} 25 elems = append(elems, fmt.Sprintf("Version: %d", pdp.Version)) 26 if pdp.Version == 0 { 27 elems = append(elems, fmt.Sprintf("TID: %d", pdp.TID)) 28 } else if pdp.Version == 1 { 29 elems = append(elems, fmt.Sprintf("TEI: %d/%d", pdp.ITEI, pdp.OTEI)) 30 } 31 elems = append(elems, fmt.Sprintf("MS-Address: %s", pdp.MSAddress)) 32 elems = append(elems, fmt.Sprintf("Peer-Address: %s", pdp.PeerAddress)) 33 return fmt.Sprintf("{%s}", strings.Join(elems, " ")) 34} 35 36func (p *PDP) parseAttributes(attrs []syscall.NetlinkRouteAttr) error { 37 for _, a := range attrs { 38 switch a.Attr.Type { 39 case nl.GENL_GTP_ATTR_VERSION: 40 p.Version = native.Uint32(a.Value) 41 case nl.GENL_GTP_ATTR_TID: 42 p.TID = native.Uint64(a.Value) 43 case nl.GENL_GTP_ATTR_PEER_ADDRESS: 44 p.PeerAddress = net.IP(a.Value) 45 case nl.GENL_GTP_ATTR_MS_ADDRESS: 46 p.MSAddress = net.IP(a.Value) 47 case nl.GENL_GTP_ATTR_FLOW: 48 p.Flow = native.Uint16(a.Value) 49 case nl.GENL_GTP_ATTR_NET_NS_FD: 50 p.NetNSFD = native.Uint32(a.Value) 51 case nl.GENL_GTP_ATTR_I_TEI: 52 p.ITEI = native.Uint32(a.Value) 53 case nl.GENL_GTP_ATTR_O_TEI: 54 p.OTEI = native.Uint32(a.Value) 55 } 56 } 57 return nil 58} 59 60func parsePDP(msgs [][]byte) ([]*PDP, error) { 61 pdps := make([]*PDP, 0, len(msgs)) 62 for _, m := range msgs { 63 attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:]) 64 if err != nil { 65 return nil, err 66 } 67 pdp := &PDP{} 68 if err := pdp.parseAttributes(attrs); err != nil { 69 return nil, err 70 } 71 pdps = append(pdps, pdp) 72 } 73 return pdps, nil 74} 75 76func (h *Handle) GTPPDPList() ([]*PDP, error) { 77 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 78 if err != nil { 79 return nil, err 80 } 81 msg := &nl.Genlmsg{ 82 Command: nl.GENL_GTP_CMD_GETPDP, 83 Version: nl.GENL_GTP_VERSION, 84 } 85 req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_DUMP) 86 req.AddData(msg) 87 msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0) 88 if err != nil { 89 return nil, err 90 } 91 return parsePDP(msgs) 92} 93 94func GTPPDPList() ([]*PDP, error) { 95 return pkgHandle.GTPPDPList() 96} 97 98func gtpPDPGet(req *nl.NetlinkRequest) (*PDP, error) { 99 msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0) 100 if err != nil { 101 return nil, err 102 } 103 pdps, err := parsePDP(msgs) 104 if err != nil { 105 return nil, err 106 } 107 if len(pdps) != 1 { 108 return nil, fmt.Errorf("invalid reqponse for GENL_GTP_CMD_GETPDP") 109 } 110 return pdps[0], nil 111} 112 113func (h *Handle) GTPPDPByTID(link Link, tid int) (*PDP, error) { 114 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 115 if err != nil { 116 return nil, err 117 } 118 msg := &nl.Genlmsg{ 119 Command: nl.GENL_GTP_CMD_GETPDP, 120 Version: nl.GENL_GTP_VERSION, 121 } 122 req := h.newNetlinkRequest(int(f.ID), 0) 123 req.AddData(msg) 124 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(0))) 125 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) 126 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(uint64(tid)))) 127 return gtpPDPGet(req) 128} 129 130func GTPPDPByTID(link Link, tid int) (*PDP, error) { 131 return pkgHandle.GTPPDPByTID(link, tid) 132} 133 134func (h *Handle) GTPPDPByITEI(link Link, itei int) (*PDP, error) { 135 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 136 if err != nil { 137 return nil, err 138 } 139 msg := &nl.Genlmsg{ 140 Command: nl.GENL_GTP_CMD_GETPDP, 141 Version: nl.GENL_GTP_VERSION, 142 } 143 req := h.newNetlinkRequest(int(f.ID), 0) 144 req.AddData(msg) 145 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(1))) 146 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) 147 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(uint32(itei)))) 148 return gtpPDPGet(req) 149} 150 151func GTPPDPByITEI(link Link, itei int) (*PDP, error) { 152 return pkgHandle.GTPPDPByITEI(link, itei) 153} 154 155func (h *Handle) GTPPDPByMSAddress(link Link, addr net.IP) (*PDP, error) { 156 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 157 if err != nil { 158 return nil, err 159 } 160 msg := &nl.Genlmsg{ 161 Command: nl.GENL_GTP_CMD_GETPDP, 162 Version: nl.GENL_GTP_VERSION, 163 } 164 req := h.newNetlinkRequest(int(f.ID), 0) 165 req.AddData(msg) 166 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(0))) 167 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) 168 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_MS_ADDRESS, []byte(addr.To4()))) 169 return gtpPDPGet(req) 170} 171 172func GTPPDPByMSAddress(link Link, addr net.IP) (*PDP, error) { 173 return pkgHandle.GTPPDPByMSAddress(link, addr) 174} 175 176func (h *Handle) GTPPDPAdd(link Link, pdp *PDP) error { 177 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 178 if err != nil { 179 return err 180 } 181 msg := &nl.Genlmsg{ 182 Command: nl.GENL_GTP_CMD_NEWPDP, 183 Version: nl.GENL_GTP_VERSION, 184 } 185 req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_EXCL|syscall.NLM_F_ACK) 186 req.AddData(msg) 187 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version))) 188 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) 189 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_PEER_ADDRESS, []byte(pdp.PeerAddress.To4()))) 190 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_MS_ADDRESS, []byte(pdp.MSAddress.To4()))) 191 192 switch pdp.Version { 193 case 0: 194 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(pdp.TID))) 195 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_FLOW, nl.Uint16Attr(pdp.Flow))) 196 case 1: 197 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(pdp.ITEI))) 198 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_O_TEI, nl.Uint32Attr(pdp.OTEI))) 199 default: 200 return fmt.Errorf("unsupported GTP version: %d", pdp.Version) 201 } 202 _, err = req.Execute(syscall.NETLINK_GENERIC, 0) 203 return err 204} 205 206func GTPPDPAdd(link Link, pdp *PDP) error { 207 return pkgHandle.GTPPDPAdd(link, pdp) 208} 209 210func (h *Handle) GTPPDPDel(link Link, pdp *PDP) error { 211 f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME) 212 if err != nil { 213 return err 214 } 215 msg := &nl.Genlmsg{ 216 Command: nl.GENL_GTP_CMD_DELPDP, 217 Version: nl.GENL_GTP_VERSION, 218 } 219 req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_EXCL|syscall.NLM_F_ACK) 220 req.AddData(msg) 221 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version))) 222 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index)))) 223 224 switch pdp.Version { 225 case 0: 226 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(pdp.TID))) 227 case 1: 228 req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(pdp.ITEI))) 229 default: 230 return fmt.Errorf("unsupported GTP version: %d", pdp.Version) 231 } 232 _, err = req.Execute(syscall.NETLINK_GENERIC, 0) 233 return err 234} 235 236func GTPPDPDel(link Link, pdp *PDP) error { 237 return pkgHandle.GTPPDPDel(link, pdp) 238} 239