#pragma once #include #include extern "C" { #include #include #include #include #include #include #include #include #include #include } enum AddressInfoType { ADDRESS_INFO_TYPE_IPV4, ADDRESS_INFO_TYPE_IPV6 }; enum AddressInfoDir { ADDRESS_INFO_C_TO_I, ADDRESS_INFO_I_TO_C }; struct AddressInfo { enum AddressInfoType type; enum AddressInfoDir dir; uint8_t src_mac_addr[6]; uint8_t dst_mac_addr[6]; uint32_t tun_vpn_id; uint32_t tun_link_id; union { struct in_addr src_addr_v4; struct in6_addr src_addr_v6; }; union { struct in_addr dst_addr_v4; struct in6_addr dst_addr_v6; }; uint32_t s_port; uint32_t d_port; }; /* 隧道格式类型 */ enum tunnel_type { TUNNEL_TYPE_UNKNOWN, TUNNEL_TYPE_END, TUNNEL_TYPE_G_VXLAN, TUNNEL_TYPE_G_MAC_IN_MAC, TUNNEL_TYPE_VLAN_FLIPPING, TUNNEL_TYPE_ETHER, TUNNEL_TYPE_PPP, TUNNEL_TYPE_HDLC, TUNNEL_TYPE_IPV4, TUNNEL_TYPE_IPV6, }; class Tunnel { protected: /* 本层隧道类型 */ enum tunnel_type this_layer_type; /* 本层隧道偏移量 */ unsigned int this_layer_length; /* 下一层隧道类型 */ enum tunnel_type next_layer_type; public: virtual enum tunnel_type NextTunType() { return next_layer_type; } virtual enum tunnel_type ThisTunType() { return this_layer_type; } virtual unsigned int ThisTunLength() { return this_layer_length; } virtual int CtrlZoneParse(struct mr_tunnat_ctrlzone * ctrlzone) { return RT_ERR; } virtual int PacketParse(const char * pkt, unsigned int pkt_len) { return RT_ERR; } virtual int PacketConstruct(const char * pkt, unsigned int pkt_len) { return RT_ERR; } virtual void MbufMetaPreParse(marsio_buff_t * mbuf) {} virtual void MbufMetaConstruct(marsio_buff_t * mbuf) {} virtual void ReverseAddress() {} virtual int GetAddressInfo(struct AddressInfo & addr_info) { return RT_ERR; } virtual size_t ToHashKey(char * out_hashkey, size_t sz_hash_key) const { assert(0); return 0; } virtual cJSON * ToJSON() const { return nullptr; } static int PacketForwardModify(const char * pkt, unsigned int pkt_len) { assert(0); return RT_ERR; } static int MbufMetaForwardModify(marsio_buff_t * mbuf) { assert(0); return RT_ERR; } }; class TunVxlan : public Tunnel { protected: struct ether_hdr ether_hdr_; struct vlan_hdr vlan_hdr_; struct ipv4_hdr ipv4_hdr_; struct udp_hdr udp_hdr_; struct g_vxlan_hdr vxlan_hdr_; private: static unsigned int __to_vpn_id(const struct g_vxlan_hdr & vxlan_hdr) { return (unsigned int)((vxlan_hdr.vlan_id_half_low & 0xfU) | (vxlan_hdr.vlan_id_half_high & 0xffU) << 4U); } public: int PacketParse(const char * pkt, unsigned int pkt_len) override; int CtrlZoneParse(struct mr_tunnat_ctrlzone * ctrlzone) override; int PacketConstruct(const char * pkt, unsigned int pkt_len) override; int GetAddressInfo(struct AddressInfo & addr_info) override { /* g-device always use IPv4 protocol */ addr_info.type = ADDRESS_INFO_TYPE_IPV4; addr_info.dir = (enum AddressInfoDir)vxlan_hdr_.dir; /* Tuple-4 */ addr_info.src_addr_v4.s_addr = ipv4_hdr_.src_addr; addr_info.dst_addr_v4.s_addr = ipv4_hdr_.dst_addr; addr_info.s_port = udp_hdr_.src_port; addr_info.d_port = udp_hdr_.dst_port; /* VxLAN, g-device used */ addr_info.tun_vpn_id = __to_vpn_id(vxlan_hdr_); addr_info.tun_link_id = vxlan_hdr_.link_id; return RT_SUCCESS; } size_t ToHashKey(char * out_hashkey, size_t sz_hash_key) const override; cJSON * ToJSON() const override; void ReverseAddress() override { vxlan_hdr_.dir = ~vxlan_hdr_.dir; } bool operator==(const TunVxlan & rt); static int PacketForwardModify(const char * pkt, unsigned int pkt_len); }; class TunQMac : public Tunnel {}; class TunVlanFlipping : public Tunnel { public: tunnel_type NextTunType() override { return TUNNEL_TYPE_ETHER; } tunnel_type ThisTunType() override { return TUNNEL_TYPE_VLAN_FLIPPING; } unsigned int ThisTunLength() override { return 0; } int PacketParse(const char * pkt, unsigned int pkt_len) override; int PacketConstruct(const char * pkt, unsigned int pkt_len) override; void MbufMetaPreParse(marsio_buff_t * mbuf) override; void MbufMetaConstruct(marsio_buff_t * mbuf) override; size_t ToHashKey(char * out_hashkey, size_t sz_hash_key) const override; cJSON * ToJSON() const override; int GetAddressInfo(struct AddressInfo & info) override; bool operator==(const TunVlanFlipping & rhs) const; public: static int PacketForwardModify(const char * pkt, unsigned int pkt_len); static int MbufMetaForwardModify(marsio_buff_t * mbuf); private: uint16_t vlan_id_; uint16_t vlan_id_map_; bool mac_flipping_; bool is_c_router_; bool vlan_id_offload_by_nic_{false}; static bool flipping_map_lookup(uint16_t le_vlan_id, uint16_t & vlan_id_out, bool & en_mac_flipping, bool & is_c_router); }; class TunInnerEther : public Tunnel { protected: constexpr static int SZ_ETHER_TUNNEL_STORAGE = 64; struct ether_hdr ether_hdr_; char ether_tunnel_on_stack_[SZ_ETHER_TUNNEL_STORAGE]; size_t ether_tunnel_len_; public: int PacketParse(const char * pkt, unsigned int pkt_len) override; int GetAddressInfo(struct AddressInfo & info) override { memcpy(info.src_mac_addr, ðer_hdr_.s_addr, sizeof(info.src_mac_addr)); memcpy(info.dst_mac_addr, ðer_hdr_.d_addr, sizeof(info.dst_mac_addr)); return RT_SUCCESS; } int PacketConstruct(const char * pkt, unsigned int pkt_len) override; void ReverseAddress() override { std::swap(ether_hdr_.s_addr, ether_hdr_.d_addr); } static int PacketForwardModify(const char * pkt, unsigned int pkt_len) { return 0; } bool operator==(const TunInnerEther & rt); size_t ToHashKey(char * out_hashkey, size_t sz_hash_key) const override; cJSON * ToJSON() const override; }; class TunInnerIPv4 : public Tunnel { protected: struct in_addr in_addr_src; struct in_addr in_addr_dst; in_port_t in_port_src; in_port_t in_port_dst; public: int PacketParse(const char * pkt, unsigned int pkt_len) override; int GetAddressInfo(struct AddressInfo & info) override { info.type = ADDRESS_INFO_TYPE_IPV4; info.src_addr_v4 = in_addr_src; info.dst_addr_v4 = in_addr_dst; info.s_port = in_port_src; info.d_port = in_port_dst; return RT_SUCCESS; } void ReverseAddress() override { std::swap(in_addr_src, in_addr_dst); std::swap(in_port_src, in_port_dst); } cJSON * ToJSON() const override; }; class TunInnerIPv6 : public Tunnel { protected: struct in6_addr in6_addr_src; struct in6_addr in6_addr_dst; in_port_t in6_port_src; in_port_t in6_port_dst; public: int PacketParse(const char * pkt, unsigned int pkt_len) override; int GetAddressInfo(struct AddressInfo & info) override { info.type = ADDRESS_INFO_TYPE_IPV6; info.src_addr_v6 = in6_addr_src; info.dst_addr_v6 = in6_addr_dst; info.s_port = in6_port_src; info.d_port = in6_port_src; return RT_SUCCESS; } void ReverseAddress() override { std::swap(in6_addr_src, in6_addr_dst); std::swap(in6_port_src, in6_port_dst); } cJSON * ToJSON() const override; }; class TunInnerPPP : public Tunnel { public: int PacketParse(const char * pkt, unsigned int pkt_len) override; int PacketConstruct(const char * pkt, unsigned int pkt_len) override { *(uint32_t *)pkt = ppp_header_; return 0; } static int PacketForwardModify(const char * pkt, unsigned int pkt_len) { return 0; } void ReverseAddress() override {} protected: uint32_t ppp_header_; }; class TunInnerHDLC : public Tunnel { public: int PacketParse(const char * pkt, unsigned int pkt_len) override; int PacketConstruct(const char * pkt, unsigned int pkt_len) override { *(uint32_t *)pkt = hdlc_header_; return 0; } static int PacketForwardModify(const char * pkt, unsigned int pkt_len) { return 0; } void ReverseAddress() override {} protected: uint32_t hdlc_header_; }; class TunnelContainer { public: int ThisTunLength(); enum tunnel_type ThisTunType(); enum tunnel_type NextTunType(); int PacketParse(const char * pkt, unsigned int pkt_len, enum tunnel_type tunnel_type = TUNNEL_TYPE_UNKNOWN); void MbufMetaPreParse(marsio_buff_t * mbuf, enum tunnel_type tunnel_type = TUNNEL_TYPE_UNKNOWN); int PacketConstruct(const char * pkt, unsigned int pkt_len); void MbufMetaConstruct(marsio_buff_t * mbuf); int GetAddressInfo(struct AddressInfo & addr_info); void ReverseAddress(); static int PacketForwardModify(const char * pkt, unsigned int pkt_len, enum tunnel_type tun_type); static int MbufMetaForwardModify(marsio_buff_t * mbuf, enum tunnel_type tun_type); protected: TunVxlan tun_vxlan_object_; TunQMac tun_qmac_object_; TunVlanFlipping tun_vlan_flipping_object; TunInnerEther tun_inner_ether_; TunInnerHDLC tun_inner_hdlc_; TunInnerPPP tun_inner_ppp_; TunInnerIPv4 tun_inner_ipv4_; TunInnerIPv6 tun_inner_ipv6_; enum tunnel_type this_layer_type; Tunnel * tun_object_; public: TunnelContainer() : this_layer_type(TUNNEL_TYPE_UNKNOWN), tun_object_(nullptr) {} TunnelContainer(const TunnelContainer & orin) : tun_vxlan_object_(orin.tun_vxlan_object_), tun_qmac_object_(orin.tun_qmac_object_), tun_vlan_flipping_object(orin.tun_vlan_flipping_object), tun_inner_ether_(orin.tun_inner_ether_), tun_inner_hdlc_(orin.tun_inner_hdlc_), tun_inner_ppp_(orin.tun_inner_ppp_), tun_inner_ipv4_(orin.tun_inner_ipv4_), tun_inner_ipv6_(orin.tun_inner_ipv6_), this_layer_type(orin.this_layer_type), tun_object_(tun_object_get()) {} TunnelContainer & operator=(const TunnelContainer & orin) { this->tun_vxlan_object_ = orin.tun_vxlan_object_; this->tun_qmac_object_ = orin.tun_qmac_object_; this->tun_vlan_flipping_object = orin.tun_vlan_flipping_object; this->tun_inner_ether_ = orin.tun_inner_ether_; this->tun_inner_hdlc_ = orin.tun_inner_hdlc_; this->tun_inner_ppp_ = orin.tun_inner_ppp_; this->tun_inner_ipv4_ = orin.tun_inner_ipv4_; this->tun_inner_ipv6_ = orin.tun_inner_ipv6_; this->this_layer_type = orin.this_layer_type; tun_object_ = tun_object_get(); return *this; } bool operator==(const TunnelContainer & rhs); bool operator!=(const TunnelContainer & rhs) { return !operator==(rhs); }; virtual size_t ToHashKey(char * out_hashkey, size_t sz_hash_key) const { return tun_object_->ToHashKey(out_hashkey, sz_hash_key); } virtual cJSON * ToJSON() const { return tun_object_->ToJSON(); } private: Tunnel * tun_object_get(); }; #define MR_TUNNAT_LAYER_MAX 4 using tunnat_link_id_t = uint64_t; struct TunnelContainerArray { std::array tun_array; unsigned int sz_array; unsigned int sz_total_len; tunnat_link_id_t v_link_id; TunnelContainerArray() : sz_array(0), sz_total_len(0) {} TunnelContainer & GetInnerTunContainer() { return tun_array[sz_array == 0 ? 0 : sz_array - 1]; } TunnelContainer & GetOuterTunContainer() { return tun_array[0]; } TunnelContainer * GetTunContainerWithType(enum tunnel_type type) { for (unsigned int i = 0; i < sz_array; i++) { auto & tun_container = tun_array[i]; if (tun_container.ThisTunType() == type) return &tun_container; } return nullptr; } void ConstructFromMbuf(marsio_buff_t * mbuf) { assert(sz_total_len == 0); assert(sz_array == 0); for (auto & tun_container : tun_array) { tun_container.MbufMetaPreParse(mbuf); } const char * pkt_ptr = marsio_buff_mtod(mbuf); unsigned int pkt_len = marsio_buff_datalen(mbuf); ConstructFromPktPtr(pkt_ptr, pkt_len); } void ConstructFromPktPtr(const char * pkt_ptr, unsigned int pkt_len) { assert(sz_total_len == 0); assert(sz_array == 0); tunnel_type pkt_tun_type = TUNNEL_TYPE_UNKNOWN; for (auto & tun_container : tun_array) { int ret = tun_container.PacketParse(pkt_ptr, pkt_len, pkt_tun_type); if (ret < 0) break; pkt_ptr += tun_container.ThisTunLength(); pkt_len -= tun_container.ThisTunLength(); pkt_tun_type = tun_container.NextTunType(); sz_array++; sz_total_len += tun_container.ThisTunLength(); if (pkt_tun_type == TUNNEL_TYPE_END) break; } } void Reset() { sz_array = 0, sz_total_len = 0; } void ReverseAddress() { for (unsigned i = 0; i < sz_array; i++) tun_array[i].ReverseAddress(); } bool LinkTunnelCompare(const struct TunnelContainerArray & rhs) { unsigned int outer_tunnel_offset = sz_array == 0 ? 0 : sz_array - 1; /* Outer Tunnel, Ether->IPv4->VxLAN->Inner Ether->Inner IPv4 * We compare from Ether to Inner Ether */ for(unsigned int iter = 0; iter < outer_tunnel_offset; iter++) { if(!(tun_array[iter] == rhs.tun_array[iter])) return false; } return true; } size_t LinkTunnelToHashKey(char * out_hash_index, size_t sz_out_hash_index) const { unsigned int outer_tunnel_offset = sz_array == 0 ? 0 : sz_array - 1; size_t out_hash_index_offset = 0; for(unsigned int iter = 0; iter < outer_tunnel_offset; iter++) { assert(out_hash_index_offset < sz_out_hash_index); char * __hash_key_output = out_hash_index + out_hash_index_offset; size_t __hash_key_left = sz_out_hash_index - out_hash_index_offset; out_hash_index_offset += tun_array[iter].ToHashKey(__hash_key_output, __hash_key_left); } return out_hash_index_offset; } cJSON * ToJSON() const { cJSON * j_object = cJSON_CreateObject(); cJSON * j_object_array = cJSON_CreateArray(); unsigned int outer_tunnel_offset = sz_array == 0 ? 0 : sz_array - 1; for (unsigned int iter = 0; iter < outer_tunnel_offset; iter++) { cJSON * tun_j_object = tun_array[iter].ToJSON(); if (tun_j_object) cJSON_AddItemToArray(j_object_array, tun_j_object); } cJSON_AddNumberToObject(j_object, "virtual_link_id", v_link_id); cJSON_AddItemToObject(j_object, "tunnel", j_object_array); return j_object; } };