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