Line data Source code
1 : /*
2 : * Copyright (c) 2017 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include <stdint.h>
7 : #include <vr_defs.h>
8 : #include <base/logging.h>
9 : #include <cmn/agent_cmn.h>
10 : #include <pkt/pkt_init.h>
11 : #include <oper/vn.h>
12 : #include <pkt/control_interface.h>
13 : #include <oper/interface_common.h>
14 : #include <services/igmp_proto.h>
15 :
16 68 : IgmpHandler::IgmpHandler(Agent *agent, boost::shared_ptr<PktInfo> info,
17 68 : boost::asio::io_context &io)
18 68 : : ProtoHandler(agent, info, io), igmp_(pkt_info_->transp.igmp) {
19 68 : if (pkt_info_->ip) {
20 0 : igmp_len_ = ntohs(pkt_info_->ip->ip_len) - (pkt_info_->ip->ip_hl * 4);
21 : } else {
22 68 : igmp_len_ = 0;
23 : }
24 68 : }
25 :
26 68 : IgmpHandler::~IgmpHandler() {
27 68 : }
28 :
29 0 : bool IgmpHandler::Run() {
30 :
31 0 : HandleVmIgmpPacket();
32 :
33 0 : return true;
34 : }
35 :
36 : // Received IGMP packet handler for processing before sending to core IGMP
37 : // message decoder and handler.
38 : // Processes the IP header of the received IGMP packet
39 0 : bool IgmpHandler::HandleVmIgmpPacket() {
40 :
41 0 : IgmpProto *igmp_proto = agent()->GetIgmpProto();
42 :
43 : int iphlen;
44 : u_int32_t igmplen;
45 :
46 : const Interface *itf =
47 0 : agent()->interface_table()->FindInterface(GetInterfaceIndex());
48 0 : if (!itf || !itf->IsActive()) {
49 0 : igmp_proto->IncrStatsBadInterface();
50 0 : return true;
51 : }
52 :
53 0 : const VmInterface *vm_itf = dynamic_cast<const VmInterface *>(itf);
54 0 : if (!vm_itf || vm_itf->vmi_type() == VmInterface::VHOST) {
55 0 : igmp_proto->IncrStatsBadInterface();
56 0 : return true;
57 : }
58 :
59 0 : if (!vm_itf->igmp_enabled()) {
60 0 : igmp_proto->IncrStatsRejectedPkt();
61 0 : return true;
62 : }
63 :
64 0 : if (pkt_info_->len <
65 0 : (sizeof(struct ether_header) + ntohs(pkt_info_->ip->ip_len))) {
66 0 : igmp_proto->IncrStatsIpPktLen();
67 0 : return true;
68 : }
69 :
70 0 : iphlen = (pkt_info_->ip->ip_hl << 2);
71 0 : if (ntohs(pkt_info_->ip->ip_len) < iphlen) {
72 0 : igmp_proto->IncrStatsBadLength();
73 0 : return true;
74 : }
75 :
76 0 : igmplen = ntohs(pkt_info_->ip->ip_len) - iphlen;
77 0 : if (igmplen < IGMP_MIN_PACKET_LENGTH) {
78 0 : igmp_proto->IncrStatsBadLength();
79 0 : return true;
80 : }
81 :
82 0 : if (!CheckPacket()) {
83 0 : igmp_proto->IncrStatsBadCksum();
84 0 : return true;
85 : }
86 :
87 0 : const VnEntry *vn = vm_itf->vn();
88 0 : IgmpInfo::VnIgmpDBState *state = NULL;
89 0 : state = static_cast<IgmpInfo::VnIgmpDBState *>(vn->GetState(
90 : vn->get_table_partition()->parent(),
91 : igmp_proto->vn_listener_id()));
92 0 : if (!state) {
93 0 : igmp_proto->IncrStatsBadInterface();
94 0 : return true;
95 : }
96 :
97 0 : const VnIpam *ipam = vn->GetIpam(pkt_info_->ip_saddr);
98 0 : if (!ipam) {
99 0 : igmp_proto->IncrStatsBadInterface();
100 0 : return true;
101 : }
102 :
103 : IgmpInfo::VnIgmpDBState::IgmpSubnetStateMap::const_iterator it =
104 0 : state->igmp_state_map_.find(ipam->default_gw);
105 0 : if (it == state->igmp_state_map_.end()) {
106 0 : igmp_proto->IncrStatsBadInterface();
107 0 : return true;
108 : }
109 :
110 0 : IgmpInfo::IgmpSubnetState *igmp_intf = NULL;
111 0 : igmp_intf = it->second;
112 :
113 0 : if (pkt_info_->transp.igmp->igmp_type > IGMP_MAX_TYPE) {
114 0 : if (igmp_intf) {
115 0 : igmp_intf->IncrRxUnknown();
116 : }
117 0 : igmp_proto->IncrStatsRxUnknown();
118 0 : return true;
119 : }
120 :
121 0 : bool parse_ok = false;
122 :
123 0 : if (!igmp_intf) {
124 : /* No MIF. If we didn't process the packet, whine. */
125 0 : igmp_proto->IncrStatsBadInterface();
126 0 : return true;
127 : }
128 :
129 0 : parse_ok = igmp_proto->GetGmpProto()->GmpProcessPkt(
130 0 : vm_itf, (void *)pkt_info_->transp.igmp, igmplen,
131 0 : pkt_info_->ip_saddr, pkt_info_->ip_daddr);
132 : /* Complain if it didn't parse. */
133 0 : if (!parse_ok) {
134 0 : igmp_intf->IncrRxBadPkt(pkt_info_->transp.igmp->igmp_type);
135 : } else {
136 0 : igmp_intf->IncrRxOkPkt(pkt_info_->transp.igmp->igmp_type);
137 : }
138 :
139 0 : return true;
140 : }
141 :
142 : // Verify the checksum of the IGMP data present in the received packet
143 0 : bool IgmpHandler::CheckPacket() const {
144 :
145 0 : uint16_t checksum = igmp_->igmp_cksum;
146 0 : igmp_->igmp_cksum = 0;
147 0 : if (checksum == Csum((uint16_t *)igmp_, igmp_len_, 0))
148 0 : return true;
149 :
150 0 : return false;
151 : }
152 :
153 : // Send packet to the VMs.
154 0 : void IgmpHandler::SendPacket(const VmInterface *vm_itf, const VrfEntry *vrf,
155 : const IpAddress& gmp_addr,
156 : GmpPacket *packet) {
157 :
158 0 : if (pkt_info_->packet_buffer() == NULL) {
159 0 : pkt_info_->AllocPacketBuffer(agent(), PktHandler::IGMP, 1024, 0);
160 : }
161 :
162 0 : char *buf = (char *)pkt_info_->packet_buffer()->data();
163 0 : uint16_t buf_len = pkt_info_->packet_buffer()->data_len();
164 0 : memset(buf, 0, buf_len);
165 :
166 0 : MacAddress smac = vm_itf->GetVifMac(agent());
167 0 : MacAddress dmac = vm_itf->vm_mac();
168 :
169 0 : pkt_info_->vrf = vrf->vrf_id();
170 0 : pkt_info_->eth = (struct ether_header *)buf;
171 0 : uint16_t eth_len = 0;
172 0 : eth_len += EthHdr(buf, buf_len, vm_itf->id(), smac, dmac, ETHERTYPE_IP);
173 :
174 0 : uint16_t data_len = packet->pkt_len_;
175 :
176 0 : in_addr_t src_ip = htonl(gmp_addr.to_v4().to_ulong());
177 0 : in_addr_t dst_ip = htonl(packet->dst_addr_.to_v4().to_ulong());
178 :
179 0 : pkt_info_->ip = (struct ip *)(buf + eth_len);
180 0 : pkt_info_->transp.igmp = (struct igmp *)
181 0 : ((uint8_t *)pkt_info_->ip + sizeof(struct ip));
182 :
183 0 : data_len += sizeof(struct ip);
184 0 : IpHdr(data_len, src_ip, dst_ip, IPPROTO_IGMP, DEFAULT_IP_ID, 1);
185 :
186 0 : memcpy(((char *)pkt_info_->transp.igmp), packet->pkt_, packet->pkt_len_);
187 0 : pkt_info_->set_len(data_len + eth_len);
188 :
189 0 : Send(vm_itf->id(), pkt_info_->vrf, AgentHdr::TX_SWITCH, PktHandler::IGMP);
190 :
191 0 : IgmpProto *igmp_proto = agent()->GetIgmpProto();
192 0 : igmp_proto->IncrSendStats(vm_itf, true);
193 :
194 0 : return;
195 : }
|