OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
igmp_handler.cc
Go to the documentation of this file.
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 IgmpHandler::IgmpHandler(Agent *agent, boost::shared_ptr<PktInfo> info,
16  boost::asio::io_context &io)
17  : ProtoHandler(agent, info, io), igmp_(pkt_info_->transp.igmp) {
18  if (pkt_info_->ip) {
19  igmp_len_ = ntohs(pkt_info_->ip->ip_len) - (pkt_info_->ip->ip_hl * 4);
20  } else {
21  igmp_len_ = 0;
22  }
23 }
24 
26 }
27 
29 
31 
32  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
39 
40  IgmpProto *igmp_proto = agent()->GetIgmpProto();
41 
42  int iphlen;
43  u_int32_t igmplen;
44 
45  const Interface *itf =
47  if (!itf || !itf->IsActive()) {
48  igmp_proto->IncrStatsBadInterface();
49  return true;
50  }
51 
52  const VmInterface *vm_itf = dynamic_cast<const VmInterface *>(itf);
53  if (!vm_itf || vm_itf->vmi_type() == VmInterface::VHOST) {
54  igmp_proto->IncrStatsBadInterface();
55  return true;
56  }
57 
58  if (!vm_itf->igmp_enabled()) {
59  igmp_proto->IncrStatsRejectedPkt();
60  return true;
61  }
62 
63  if (pkt_info_->len <
64  (sizeof(struct ether_header) + ntohs(pkt_info_->ip->ip_len))) {
65  igmp_proto->IncrStatsIpPktLen();
66  return true;
67  }
68 
69  iphlen = (pkt_info_->ip->ip_hl << 2);
70  if (ntohs(pkt_info_->ip->ip_len) < iphlen) {
71  igmp_proto->IncrStatsBadLength();
72  return true;
73  }
74 
75  igmplen = ntohs(pkt_info_->ip->ip_len) - iphlen;
76  if (igmplen < IGMP_MIN_PACKET_LENGTH) {
77  igmp_proto->IncrStatsBadLength();
78  return true;
79  }
80 
81  if (!CheckPacket()) {
82  igmp_proto->IncrStatsBadCksum();
83  return true;
84  }
85 
86  const VnEntry *vn = vm_itf->vn();
87  IgmpInfo::VnIgmpDBState *state = NULL;
88  state = static_cast<IgmpInfo::VnIgmpDBState *>(vn->GetState(
89  vn->get_table_partition()->parent(),
90  igmp_proto->vn_listener_id()));
91  if (!state) {
92  igmp_proto->IncrStatsBadInterface();
93  return true;
94  }
95 
96  const VnIpam *ipam = vn->GetIpam(pkt_info_->ip_saddr);
97  if (!ipam) {
98  igmp_proto->IncrStatsBadInterface();
99  return true;
100  }
101 
102  IgmpInfo::VnIgmpDBState::IgmpSubnetStateMap::const_iterator it =
103  state->igmp_state_map_.find(ipam->default_gw);
104  if (it == state->igmp_state_map_.end()) {
105  igmp_proto->IncrStatsBadInterface();
106  return true;
107  }
108 
109  IgmpInfo::IgmpSubnetState *igmp_intf = NULL;
110  igmp_intf = it->second;
111 
112  if (pkt_info_->transp.igmp->igmp_type > IGMP_MAX_TYPE) {
113  if (igmp_intf) {
114  igmp_intf->IncrRxUnknown();
115  }
116  igmp_proto->IncrStatsRxUnknown();
117  return true;
118  }
119 
120  bool parse_ok = false;
121 
122  if (!igmp_intf) {
123  /* No MIF. If we didn't process the packet, whine. */
124  igmp_proto->IncrStatsBadInterface();
125  return true;
126  }
127 
128  parse_ok = igmp_proto->GetGmpProto()->GmpProcessPkt(
129  vm_itf, (void *)pkt_info_->transp.igmp, igmplen,
130  pkt_info_->ip_saddr, pkt_info_->ip_daddr);
131  /* Complain if it didn't parse. */
132  if (!parse_ok) {
133  igmp_intf->IncrRxBadPkt(pkt_info_->transp.igmp->igmp_type);
134  } else {
135  igmp_intf->IncrRxOkPkt(pkt_info_->transp.igmp->igmp_type);
136  }
137 
138  return true;
139 }
140 
141 // Verify the checksum of the IGMP data present in the received packet
143 
144  uint16_t checksum = igmp_->igmp_cksum;
145  igmp_->igmp_cksum = 0;
146  if (checksum == Csum((uint16_t *)igmp_, igmp_len_, 0))
147  return true;
148 
149  return false;
150 }
151 
152 // Send packet to the VMs.
153 void IgmpHandler::SendPacket(const VmInterface *vm_itf, const VrfEntry *vrf,
154  const IpAddress& gmp_addr,
155  GmpPacket *packet) {
156 
157  if (pkt_info_->packet_buffer() == NULL) {
158  pkt_info_->AllocPacketBuffer(agent(), PktHandler::IGMP, 1024, 0);
159  }
160 
161  char *buf = (char *)pkt_info_->packet_buffer()->data();
162  uint16_t buf_len = pkt_info_->packet_buffer()->data_len();
163  memset(buf, 0, buf_len);
164 
165  MacAddress smac = vm_itf->GetVifMac(agent());
166  MacAddress dmac = vm_itf->vm_mac();
167 
168  pkt_info_->vrf = vrf->vrf_id();
169  pkt_info_->eth = (struct ether_header *)buf;
170  uint16_t eth_len = 0;
171  eth_len += EthHdr(buf, buf_len, vm_itf->id(), smac, dmac, ETHERTYPE_IP);
172 
173  uint16_t data_len = packet->pkt_len_;
174 
175  in_addr_t src_ip = htonl(gmp_addr.to_v4().to_ulong());
176  in_addr_t dst_ip = htonl(packet->dst_addr_.to_v4().to_ulong());
177 
178  pkt_info_->ip = (struct ip *)(buf + eth_len);
179  pkt_info_->transp.igmp = (struct igmp *)
180  ((uint8_t *)pkt_info_->ip + sizeof(struct ip));
181 
182  data_len += sizeof(struct ip);
183  IpHdr(data_len, src_ip, dst_ip, IPPROTO_IGMP, DEFAULT_IP_ID, 1);
184 
185  memcpy(((char *)pkt_info_->transp.igmp), packet->pkt_, packet->pkt_len_);
186  pkt_info_->set_len(data_len + eth_len);
187 
189 
190  IgmpProto *igmp_proto = agent()->GetIgmpProto();
191  igmp_proto->IncrSendStats(vm_itf, true);
192 
193  return;
194 }
const MacAddress & vm_mac() const
bool HandleVmIgmpPacket()
Definition: igmp_handler.cc:38
bool GmpProcessPkt(const VmInterface *vm_itf, void *rcv_pkt, uint32_t packet_len, IpAddress ip_saddr, IpAddress ip_daddr)
Definition: gmp_proto.cc:443
Definition: vrf.h:86
DBState * GetState(DBTableBase *tbl_base, ListenerId listener) const
Definition: db_entry.cc:37
const uint32_t id() const
Definition: interface.h:123
const VnIpam * GetIpam(const IpAddress &ip) const
Definition: vn.cc:651
Definition: vn.h:28
uint8_t * pkt_
Definition: gmp_proto.h:20
boost::asio::ip::address IpAddress
Definition: address.h:13
const MacAddress & GetVifMac(const Agent *) const
#define DEFAULT_IP_ID
Definition: pkt_handler.h:48
DBTableBase * parent()
InterfaceTable * interface_table() const
Definition: agent.h:465
uint16_t Csum(uint16_t *, std::size_t, uint32_t) const
void SendPacket(const VmInterface *vm_itf, const VrfEntry *vrf, const IpAddress &gmp_addr, GmpPacket *packet)
IpAddress dst_addr_
Definition: gmp_proto.h:22
Agent * agent() const
Definition: proto_handler.h:80
boost::shared_ptr< PktInfo > pkt_info_
Definition: proto_handler.h:92
IgmpSubnetStateMap igmp_state_map_
Definition: igmp_proto.h:105
void IncrStatsRxUnknown()
Definition: igmp_proto.h:148
int EthHdr(const MacAddress &src, const MacAddress &dest, const uint16_t proto)
#define IGMP_MIN_PACKET_LENGTH
Definition: igmp_proto.h:26
IpAddress default_gw
Definition: vn.h:31
Definition: agent.h:358
uint32_t GetInterfaceIndex() const
Definition: proto_handler.h:82
void IncrStatsBadLength()
Definition: igmp_proto.h:144
IgmpProto * GetIgmpProto() const
Definition: agent.h:1002
virtual ~IgmpHandler()
Definition: igmp_handler.cc:25
void Send(uint32_t itf, uint32_t vrf, uint16_t, PktHandler::PktModuleName)
struct igmp * igmp_
Definition: igmp_handler.h:26
IgmpHandler(Agent *agent, boost::shared_ptr< PktInfo > info, boost::asio::io_context &io)
Definition: igmp_handler.cc:15
void IncrSendStats(const VmInterface *vm_itf, bool tx_done)
Definition: igmp_proto.cc:233
const VnEntry * vn() const
void IncrRxOkPkt(unsigned long index)
Definition: igmp_proto.h:73
void IncrStatsBadInterface()
Definition: igmp_proto.h:146
const uint32_t vrf_id() const
Definition: vrf.h:99
void IncrStatsBadCksum()
Definition: igmp_proto.h:145
Definition: vn.h:151
VmInterface::VmiType vmi_type() const
void IncrStatsRejectedPkt()
Definition: igmp_proto.h:149
bool igmp_enabled() const
const Interface * FindInterface(size_t index) const
Definition: interface.cc:323
bool IsActive() const
Definition: agent_db.cc:27
void IncrStatsIpPktLen()
Definition: igmp_proto.h:150
DBTablePartBase * get_table_partition() const
Definition: db_entry.cc:115
bool CheckPacket() const
DBTableBase::ListenerId vn_listener_id()
Definition: igmp_proto.cc:156
uint32_t pkt_len_
Definition: gmp_proto.h:21
void IpHdr(uint16_t len, in_addr_t src, in_addr_t dest, uint8_t protocol, uint16_t id, uint8_t ttl)
#define IGMP_MAX_TYPE
Definition: igmp_proto.h:25
void IncrRxBadPkt(unsigned long index)
Definition: igmp_proto.h:67
GmpProto * GetGmpProto()
Definition: igmp_proto.h:153
uint16_t igmp_len_
Definition: igmp_handler.h:27