Line data Source code
1 : #include <stdint.h>
2 : #include "base/os.h"
3 : #include "pkt/proto.h"
4 : #include "pkt/proto_handler.h"
5 : #include "diag/diag_types.h"
6 : #include "diag/diag_pkt_handler.h"
7 : #include "diag/diag.h"
8 : #include "diag/overlay_ping.h"
9 : #include <oper/route_common.h>
10 : #include <oper/vrf_assign.h>
11 : #include <oper/tunnel_nh.h>
12 :
13 : using namespace boost::posix_time;
14 : extern void time_duration_to_string(time_duration &td, std::string &str);
15 : const MacAddress OverlayPing::in_dst_mac_(0x00, 0x00, 0x5E, 0x90, 0x00, 0x01);
16 : const MacAddress OverlayPing::in_source_mac_(0x00, 0x00, 0x5E, 0x90, 0x00, 0x02);
17 :
18 0 : OverlayPing::OverlayPing(const OverlayPingReq *ping_req, DiagTable *diag_table):
19 : DiagEntry(ping_req->get_source_ip(), ping_req->get_dest_ip(),
20 0 : ping_req->get_protocol(), ping_req->get_source_port(),
21 0 : ping_req->get_dest_port(), Agent::GetInstance()->fabric_vrf_name(),
22 0 : ping_req->get_interval() * 100, ping_req->get_count(), diag_table),
23 0 : vn_uuid_(StringToUuid(ping_req->get_vn_uuid())),
24 0 : remote_vm_mac_(ping_req->get_vm_remote_mac()),
25 0 : data_len_(ping_req->get_packet_size()),
26 0 : context_(ping_req->context()),
27 0 : pkt_lost_count_(0) {
28 :
29 0 : }
30 : /*
31 : * Get the L2 Route entry to find the Tunnel NH
32 : */
33 : BridgeRouteEntry *
34 0 : OverlayPing::L2RouteGet(VxLanId* vxlan, string remotemac, Agent *agent)
35 : {
36 0 : string vrf_name;
37 0 : const VrfNH *vrf_nh = dynamic_cast<const VrfNH *>(vxlan->nexthop());
38 0 : VrfEntry *vrf = NULL;
39 0 : if (vrf_nh) {
40 0 : vrf = const_cast<VrfEntry*> (vrf_nh->GetVrf());
41 0 : if (!vrf || vrf->IsDeleted()) {
42 0 : return NULL;
43 : } else {
44 0 : vrf_name = vrf->GetName();
45 : }
46 : } else {
47 0 : return NULL;
48 : }
49 0 : MacAddress mac = MacAddress::FromString(remotemac);
50 0 : BridgeRouteKey key(agent->local_vm_peer(), vrf_name, mac);
51 : BridgeRouteEntry *rt = static_cast<BridgeRouteEntry *>
52 : (static_cast<BridgeAgentRouteTable *>
53 0 : (vrf->GetBridgeRouteTable())->FindActiveEntry(&key));
54 0 : return rt;
55 0 : }
56 :
57 0 : void OverlayPingReq::HandleRequest() const {
58 0 : std::string err_str;
59 0 : boost::system::error_code ec;
60 0 : OverlayPing *overlayping = NULL;
61 : {
62 0 : Agent *agent = Agent::GetInstance();
63 0 : boost::uuids::uuid vn_uuid = StringToUuid(get_vn_uuid());
64 0 : IpAddress sip(IpAddress::from_string(get_source_ip(), ec));
65 0 : if (ec.failed()) {
66 0 : err_str = "Invalid source IP";
67 0 : goto error;
68 : }
69 :
70 0 : if (!sip.is_v4()) {
71 0 : err_str = "V6 is not supported";
72 0 : goto error;
73 : }
74 :
75 0 : IpAddress dip(IpAddress::from_string(get_dest_ip(), ec));
76 0 : if (ec.failed()) {
77 0 : err_str = "Invalid destination IP";
78 0 : goto error;
79 : }
80 :
81 0 : if (!dip.is_v4()) {
82 0 : err_str = "V6 is not supported";
83 0 : goto error;
84 : }
85 :
86 0 : uint8_t proto = get_protocol();
87 0 : if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
88 0 : err_str = "Invalid protocol. Valid Protocols are TCP & UDP";
89 0 : goto error;
90 : }
91 :
92 0 : VnEntry *vn = agent->vn_table()->Find(vn_uuid);
93 0 : if (!vn) {
94 0 : err_str = "Invalid VN segment";
95 0 : goto error;
96 : }
97 :
98 0 : int vxlan_id = vn->GetVxLanId();
99 0 : VxLanId* vxlan = agent->vxlan_table()->Find(vxlan_id);
100 :
101 0 : if (!vxlan) {
102 0 : err_str = "Invalid vxlan segment";
103 0 : goto error;
104 : }
105 :
106 0 : BridgeRouteEntry *rt = OverlayPing::L2RouteGet(vxlan, get_vm_remote_mac(),
107 : agent);
108 0 : if (!rt) {
109 0 : err_str = "Invalid remote mac";
110 0 : goto error;
111 : }
112 : }
113 0 : overlayping = new OverlayPing(this, Agent::GetInstance()->diag_table());
114 0 : overlayping->Init();
115 0 : return;
116 0 : error:
117 0 : PingErrResp *resp = new PingErrResp;
118 0 : resp->set_error_response(err_str);
119 0 : resp->set_context(context());
120 0 : resp->Response();
121 0 : return;
122 0 : }
123 :
124 0 : OverlayPing::~OverlayPing() {
125 :
126 0 : }
127 :
128 : /*
129 : * Creat Overlay VXlan packet.
130 : * Set the Route alert bit to indicate Overlay OAM packet
131 : */
132 0 : void OverlayPing::SendRequest() {
133 : // Create VxLan packet
134 0 : Agent *agent = diag_table_->agent();
135 0 : Ip4Address tunneldst;
136 0 : Ip4Address tunnelsrc;
137 0 : seq_no_++;
138 0 : string vrf_name;
139 0 : boost::system::error_code ec;
140 :
141 0 : int vxlan_id = agent->vn_table()->Find(vn_uuid_)->GetVxLanId();
142 0 : VxLanId *vxlan = agent->vxlan_table()->Find(vxlan_id);
143 0 : if (!vxlan)
144 0 : return;
145 :
146 0 : BridgeRouteEntry *rt = L2RouteGet(vxlan, remote_vm_mac_.ToString(), agent);
147 0 : if (!rt)
148 0 : return;
149 0 : const AgentPath *path = rt->GetActivePath();
150 0 : const TunnelNH *nh = static_cast<const TunnelNH *>(path->nexthop());
151 :
152 0 : tunneldst = *nh->GetDip();
153 0 : tunnelsrc = *nh->GetSip();
154 0 : len_ = kOverlayUdpHdrLength + data_len_;
155 0 : boost::shared_ptr<PktInfo> pkt_info(new PktInfo(agent, len_,
156 0 : PktHandler::DIAG, 0));
157 0 : uint8_t *buf = pkt_info->packet_buffer()->data();
158 0 : memset(buf, 0, len_);
159 0 : OverlayOamPktData *pktdata = NULL;
160 0 : pktdata = (OverlayOamPktData *)(buf + kOverlayUdpHdrLength);
161 0 : memset(pktdata, 0, sizeof(OverlayOamPktData));
162 :
163 0 : senttime_ = microsec_clock::universal_time();
164 0 : FillOamPktHeader(pktdata, vxlan_id, senttime_);
165 0 : DiagPktHandler *pkt_handler = new DiagPktHandler(diag_table_->agent(), pkt_info,
166 0 : *(diag_table_->agent()->event_manager())->io_service());
167 : // Fill outer header
168 0 : pkt_info->eth = (struct ether_header *)(buf);
169 0 : pkt_handler->EthHdr(agent->vhost_interface()->mac(), *nh->GetDmac(),
170 : ETHERTYPE_IP);
171 0 : pkt_info->ip = (struct ip *)(pkt_info->eth +1);
172 0 : pkt_info->transp.udp = (struct udphdr *)(pkt_info->ip + 1);
173 : uint8_t len;
174 0 : len = data_len_+2 * sizeof(udphdr)+sizeof(VxlanHdr)+
175 0 : sizeof(struct ip) + sizeof(struct ether_header);
176 0 : pkt_handler->UdpHdr(len, ntohl(tunnelsrc.to_ulong()), HashValUdpSourcePort(),
177 0 : ntohl(tunneldst.to_ulong()), VXLAN_UDP_DEST_PORT);
178 :
179 0 : pkt_handler->IpHdr(len + sizeof(struct ip), ntohl(tunnelsrc.to_ulong()),
180 0 : ntohl(tunneldst.to_ulong()), IPPROTO_UDP,
181 : DEFAULT_IP_ID, DEFAULT_IP_TTL );
182 : // Fill VxLan Header
183 0 : VxlanHdr *vxlanhdr = (VxlanHdr *)(buf + sizeof(udphdr)+ sizeof(struct ip)
184 : + sizeof(struct ether_header));
185 0 : vxlanhdr->vxlan_id = ntohl(vxlan_id << 8);
186 0 : vxlanhdr->reserved = ntohl(kVxlanRABit | kVxlanIBit);
187 :
188 : //Fill inner packet details.
189 0 : pkt_info->eth = (struct ether_header *)(vxlanhdr + 1);
190 :
191 0 : pkt_handler->EthHdr(in_source_mac_, in_dst_mac_,
192 : ETHERTYPE_IP);
193 :
194 0 : pkt_info->ip = (struct ip *)(pkt_info->eth +1);
195 0 : Ip4Address dip = Ip4Address::from_string("127.0.0.1", ec);
196 0 : pkt_info->transp.udp = (struct udphdr *)(pkt_info->ip + 1);
197 0 : len = data_len_+sizeof(struct udphdr);
198 0 : pkt_handler->UdpHdr(len, sip_.to_v4().to_ulong(), sport_, dip.to_ulong(),
199 : VXLAN_UDP_DEST_PORT);
200 0 : pkt_handler->IpHdr(len + sizeof(struct ip), ntohl(sip_.to_v4().to_ulong()),
201 0 : ntohl(dip.to_ulong()), proto_,
202 : DEFAULT_IP_ID, DEFAULT_IP_TTL);
203 : //pkt_handler->SetDiagChkSum();
204 0 : pkt_handler->pkt_info()->set_len(len_);
205 0 : PhysicalInterfaceKey key1(agent->fabric_interface_name());
206 0 : Interface *intf = static_cast<Interface *>
207 0 : (agent->interface_table()->Find(&key1, true));
208 0 : pkt_handler->Send(intf->id(), agent->fabric_vrf()->vrf_id(),
209 : AgentHdr::TX_SWITCH, CMD_PARAM_PACKET_CTRL,
210 : CMD_PARAM_1_DIAG, PktHandler::DIAG);
211 :
212 0 : delete pkt_handler;
213 0 : return;
214 0 : }
215 :
216 0 : void OverlayPing::HandleReply(DiagPktHandler *handler) {
217 0 : PingResp *resp = new PingResp();
218 0 : OverlayOamPktData *pktdata = (OverlayOamPktData*) handler->GetData();
219 0 : resp->set_seq_no(ntohl(pktdata->seq_no_));
220 0 : boost::posix_time::ptime time = microsec_clock::universal_time();
221 0 : boost::posix_time::time_duration rtt = time - senttime_;
222 0 : avg_rtt_ += rtt;
223 0 : std::string rtt_str;
224 0 : time_duration_to_string(rtt, rtt_str);
225 0 : resp->set_rtt(rtt_str);
226 0 : resp->set_resp("Success");
227 0 : resp->set_context(context_);
228 0 : resp->set_more(true);
229 0 : resp->Response();
230 0 : }
231 :
232 0 : void OverlayPing::RequestTimedOut(uint32_t seq_no) {
233 0 : PingResp *resp = new PingResp();
234 0 : pkt_lost_count_++;
235 0 : resp->set_resp("Timed Out");
236 0 : resp->set_seq_no(seq_no_);
237 0 : resp->set_context(context_);
238 0 : resp->set_more(true);
239 0 : resp->Response();
240 0 : }
241 :
242 0 : void OverlayPing::SendSummary(){
243 0 : PingSummaryResp *resp = new PingSummaryResp();
244 :
245 0 : if (pkt_lost_count_ != GetMaxAttempts()) {
246 : //If we had some succesful replies, send in
247 : //average rtt for succesful ping requests
248 0 : avg_rtt_ = (avg_rtt_ / (seq_no_ - pkt_lost_count_));
249 0 : std::string avg_rtt_string;
250 0 : time_duration_to_string(avg_rtt_, avg_rtt_string);
251 0 : resp->set_average_rtt(avg_rtt_string);
252 0 : }
253 0 : resp->set_request_sent(seq_no_);
254 0 : resp->set_response_received(seq_no_ - pkt_lost_count_);
255 0 : uint32_t pkt_loss_percent = (pkt_lost_count_ * 100/seq_no_);
256 0 : resp->set_pkt_loss(pkt_loss_percent);
257 0 : resp->set_context(context_);
258 0 : resp->Response();
259 0 : }
|