OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
igmp_proto.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include "cmn/agent_cmn.h"
6 #include "init/agent_param.h"
7 #include "oper/vn.h"
8 #include "oper/route_common.h"
9 #include "oper/multicast.h"
10 #include "services/igmp_proto.h"
11 
12 IgmpProto::IgmpProto(Agent *agent, boost::asio::io_context &io) :
13  Proto(agent, "Agent::Services", PktHandler::IGMP, io),
14  task_name_("Agent::Services"), io_(io) {
15 
16  IgmpProtoInit();
17 }
18 
20 }
21 
23 
24  // limit the number of entries in the workqueue
26  work_queue_.SetBounded(true);
27 
30  if (gmp_proto_) {
32  boost::bind(&IgmpProto::SendIgmpPacket, this, _1, _2, _3));
33  gmp_proto_->Start();
34  }
35 
37  boost::bind(&IgmpProto::VnNotify, this, _1, _2));
38 
39  ClearStats();
40 }
41 
43 
45 
46  if (gmp_proto_) {
47  gmp_proto_->Stop();
49  }
50 }
51 
52 ProtoHandler *IgmpProto::AllocProtoHandler(boost::shared_ptr<PktInfo> info,
53  boost::asio::io_context &io) {
54  return new IgmpHandler(agent(), info, io);
55 }
56 
58 
59  // Registering/Unregistering every IPAM gateway (or) dns_server
60  // present in the VN with the IGMP module.
61  // Changes to VN, or VN IPAM info, or gateway or dns server is
62  // handled below.
63 
64  VnEntry *vn = static_cast<VnEntry *>(entry);
65  IgmpInfo::IgmpSubnetState *igmp_intf = NULL;
66 
68  static_cast<IgmpInfo::VnIgmpDBState *>
69  (entry->GetState(part->parent(), vn_listener_id_));
70 
71  if (vn->IsDeleted() || !vn->GetVrf()) {
72  if (!state) {
73  return;
74  }
75  IgmpInfo::VnIgmpDBState::IgmpSubnetStateMap::iterator it =
76  state->igmp_state_map_.begin();
77  for (;it != state->igmp_state_map_.end(); ++it) {
78  igmp_intf = it->second;
79  delete igmp_intf;
80  }
81  state->igmp_state_map_.clear();
82 
83  if (vn->IsDeleted()) {
84  entry->ClearState(part->parent(), vn_listener_id_);
85  delete state;
86  }
87  return;
88  }
89 
90  if (!vn->GetVrf()) {
91  return;
92  }
93 
94  if ((vn->GetVrf()->GetName() == agent_->fabric_policy_vrf_name()) ||
95  (vn->GetVrf()->GetName() == agent_->fabric_vrf_name())) {
96  return;
97  }
98 
99  if (state == NULL) {
100  state = new IgmpInfo::VnIgmpDBState();
101 
102  entry->SetState(part->parent(), vn_listener_id_, state);
103  }
104 
105  IgmpInfo::VnIgmpDBState::IgmpSubnetStateMap::iterator it =
106  state->igmp_state_map_.begin();
107  while (it != state->igmp_state_map_.end()) {
108  const VnIpam *ipam = vn->GetIpam(it->first);
109  if ((ipam != NULL) && ((ipam->default_gw == it->first) ||
110  (ipam->dns_server == it->first))) {
111  it++;
112  continue;
113  }
114  igmp_intf = it->second;
115  delete igmp_intf;
116  state->igmp_state_map_.erase(it++);
117  }
118 
119  const std::vector<VnIpam> &ipam = vn->GetVnIpam();
120  for (unsigned int i = 0; i < ipam.size(); ++i) {
121  if (!ipam[i].IsV4()) {
122  continue;
123  }
124  if ((ipam[i].default_gw == IpAddress(Ip4Address())) &&
125  (ipam[i].dns_server == IpAddress(Ip4Address()))) {
126  continue;
127  }
128 
129  IpAddress igmp_address = IpAddress(Ip4Address());
130  IgmpInfo::VnIgmpDBState::IgmpSubnetStateMap::const_iterator it;
131 
132  if (ipam[i].dns_server != IpAddress(Ip4Address())) {
133  it = state->igmp_state_map_.find(ipam[i].dns_server);
134  igmp_address = ipam[i].dns_server;
135  }
136  if (ipam[i].default_gw != IpAddress(Ip4Address())) {
137  if (it != state->igmp_state_map_.end()) {
138  igmp_intf = it->second;
139  delete igmp_intf;
140  state->igmp_state_map_.erase(it->first);
141  }
142 
143  igmp_address = ipam[i].default_gw;
144  }
145 
146  it = state->igmp_state_map_.find(igmp_address);
147  if (it == state->igmp_state_map_.end()) {
148  igmp_intf = new IgmpInfo::IgmpSubnetState;
149  state->igmp_state_map_.insert(
150  std::pair<IpAddress, IgmpInfo::IgmpSubnetState*>
151  (igmp_address, igmp_intf));
152  }
153  }
154 }
155 
157  return vn_listener_id_;
158 }
159 
160 // Send IGMP packets to the VMs part of the IPAM VN
161 bool IgmpProto::SendIgmpPacket(const VrfEntry *vrf, IpAddress gmp_addr,
162  GmpPacket *packet) {
163 
164  if (!vrf || !packet) {
165  return false;
166  }
167 
168  if (!gmp_addr.is_v4()) {
169  return false;
170  }
171 
172  VnEntry *vn = vrf->vn();
173  if (!vn) {
174  return false;
175  }
176 
177  const VnIpam *ipam = vn->GetIpam(gmp_addr);
178  if (!ipam) {
179  return false;
180  }
181 
182  Ip4Address subnet = (ipam->GetSubnetAddress()).to_v4();
183  InetUnicastAgentRouteTable *inet_table =
185  const InetUnicastRouteEntry *rt = inet_table->FindRoute(subnet);
186  if (!rt) {
187  return false;
188  }
189 
190  boost::shared_ptr<PktInfo> pkt(new PktInfo(agent_, 1024, PktHandler::IGMP,
191  0));
192  IgmpHandler igmp_handler(agent_, pkt,
193  *(agent_->event_manager()->io_service()));
194 
195  do {
196  const NextHop *nh = rt->GetActiveNextHop();
197  if (!nh || nh->IsDeleted()) {
198  continue;
199  }
200  const InterfaceNH *inh = dynamic_cast<const InterfaceNH *>(nh);
201  if (!inh) {
202  continue;
203  }
204  const Interface *itf = inh->GetInterface();
205  if (!itf) {
206  continue;
207  }
208  const VmInterface *vm_itf = dynamic_cast<const VmInterface *>(itf);
209  if (!vm_itf || vm_itf->IsDeleted()) {
210  continue;
211  }
212  if (vm_itf->vmi_type() == VmInterface::VHOST) {
213  continue;
214  }
215  if (vm_itf->vrf() && vrf->GetName() != vm_itf->vrf()->GetName()) {
216  continue;
217  }
218  if (!ipam->IsSubnetMember(IpAddress(vm_itf->primary_ip_addr()))) {
219  break;
220  }
221  if (!vm_itf->igmp_enabled()) {
222  IncrSendStats(vm_itf, false);
223  continue;
224  }
225 
226  igmp_handler.SendPacket(vm_itf, vrf, gmp_addr, packet);
227 
228  } while ((rt = inet_table->GetNext(rt)) != NULL);
229 
230  return true;
231 }
232 
233 void IgmpProto::IncrSendStats(const VmInterface *vm_itf, bool tx_done) {
234 
235  const VnEntry *vn = vm_itf->vn();
236  IgmpInfo::VnIgmpDBState *state = NULL;
237  state = static_cast<IgmpInfo::VnIgmpDBState *>(vn->GetState(
238  vn->get_table_partition()->parent(),
239  vn_listener_id()));
240  if (!state) {
241  return;
242  }
243  const VnIpam *ipam = vn->GetIpam(vm_itf->primary_ip_addr());
244  if (!ipam) {
245  return;
246  }
247  IgmpInfo::VnIgmpDBState::IgmpSubnetStateMap::const_iterator it =
248  state->igmp_state_map_.find(ipam->default_gw);
249  if (it == state->igmp_state_map_.end()) {
250  return;
251  }
252 
253  IgmpInfo::IgmpSubnetState *igmp_intf = NULL;
254  igmp_intf = it->second;
255 
256  if (tx_done) {
257  igmp_intf->IncrTxPkt();
258  } else {
259  igmp_intf->IncrTxDropPkt();
260  }
261 
262  return;
263 }
264 
265 const bool IgmpProto::GetItfStats(const VnEntry *vn, IpAddress gateway,
266  IgmpInfo::IgmpItfStats &stats) {
267 
268  const VnIpam *ipam = vn->GetIpam(gateway);
269  if (!ipam) {
270  return false;
271  }
272 
273  IgmpInfo::VnIgmpDBState *state = NULL;
274  state = static_cast<IgmpInfo::VnIgmpDBState *>(vn->GetState(
276  if (!state) {
277  return false;
278  }
279 
280  IgmpInfo::VnIgmpDBState::IgmpSubnetStateMap::const_iterator it =
281  state->igmp_state_map_.find(ipam->default_gw);
282  if (it == state->igmp_state_map_.end()) {
283  return false;
284  }
285 
286  IgmpInfo::IgmpSubnetState *igmp_intf = it->second;
287 
288  stats = igmp_intf->GetItfStats();
289 
290  return true;
291 }
292 
293 void IgmpProto::ClearItfStats(const VnEntry *vn, IpAddress gateway) {
294 
295  if (!vn) {
296  return;
297  }
298 
299  const VnIpam *ipam = vn->GetIpam(gateway);
300  if (!ipam) {
301  return;
302  }
303 
304  IgmpInfo::VnIgmpDBState *state = NULL;
305  state = static_cast<IgmpInfo::VnIgmpDBState *>(vn->GetState(
307  if (!state) {
308  return;
309  }
310 
311  IgmpInfo::VnIgmpDBState::IgmpSubnetStateMap::const_iterator it =
312  state->igmp_state_map_.find(ipam->default_gw);
313  if (it == state->igmp_state_map_.end()) {
314  return;
315  }
316 
317  IgmpInfo::IgmpSubnetState *igmp_intf = it->second;
318  igmp_intf->ClearItfStats();
319 
320  return;
321 }
void SetBounded(bool bounded)
Definition: queue_task.h:200
const Interface * GetInterface() const
Definition: nexthop.h:1293
static GmpProto * CreateGmpProto(GmpType::Type type, Agent *agent, const std::string &name, int instance, boost::asio::io_context &io)
Definition: gmp_proto.cc:804
Definition: vrf.h:86
DBTableBase::ListenerId vn_listener_id_
Definition: igmp_proto.h:172
DBState * GetState(DBTableBase *tbl_base, ListenerId listener) const
Definition: db_entry.cc:37
void Shutdown()
Definition: igmp_proto.cc:42
bool Stop()
Definition: gmp_proto.cc:139
static bool DeleteGmpProto(GmpProto *gmp_proto)
Definition: gmp_proto.cc:816
const VnIpam * GetIpam(const IpAddress &ip) const
Definition: vn.cc:651
Definition: vn.h:28
bool SendIgmpPacket(const VrfEntry *vrf, IpAddress gmp_addr, GmpPacket *packet)
Definition: igmp_proto.cc:161
bool IsDeleted() const
Definition: db_entry.h:49
void SetState(DBTableBase *tbl_base, ListenerId listener, DBState *state)
Definition: db_entry.cc:22
boost::asio::ip::address IpAddress
Definition: address.h:13
int ListenerId
Definition: db_table.h:62
boost::asio::io_context & io_
Definition: igmp_proto.h:170
boost::asio::io_context * io_service()
Definition: event_manager.h:42
InetUnicastAgentRouteTable * GetInet4UnicastRouteTable() const
Definition: vrf.cc:319
DBTableBase * parent()
VnTable * vn_table() const
Definition: agent.h:495
void VnNotify(DBTablePartBase *part, DBEntryBase *entry)
Definition: igmp_proto.cc:57
IpAddress GetSubnetAddress() const
Definition: vn.cc:63
InetUnicastRouteEntry * FindRoute(const IpAddress &ip)
const string & GetName() const
Definition: vrf.h:100
bool Start()
Definition: gmp_proto.cc:98
void SendPacket(const VmInterface *vm_itf, const VrfEntry *vrf, const IpAddress &gmp_addr, GmpPacket *packet)
VrfEntry * vrf() const
Definition: interface.h:115
void ClearStats()
Definition: igmp_proto.h:152
const std::string task_name_
Definition: igmp_proto.h:169
void Unregister(ListenerId listener)
Definition: db_table.cc:186
IgmpSubnetStateMap igmp_state_map_
Definition: igmp_proto.h:105
bool IsSubnetMember(const IpAddress &ip) const
Definition: vn.cc:73
ListenerId Register(ChangeCallback callback, const std::string &name="unspecified")
Definition: db_table.cc:181
const std::string & fabric_vrf_name() const
Definition: agent.h:903
IpAddress default_gw
Definition: vn.h:31
void SetSize(size_t size)
Definition: queue_task.h:196
Definition: agent.h:358
const NextHop * GetActiveNextHop() const
Definition: agent_route.cc:881
EventManager * event_manager() const
Definition: agent.h:1103
GmpProto * gmp_proto_
Definition: igmp_proto.h:174
virtual ~IgmpProto()
Definition: igmp_proto.cc:19
const InetUnicastRouteEntry * GetNext(const InetUnicastRouteEntry *rt)
void IncrSendStats(const VmInterface *vm_itf, bool tx_done)
Definition: igmp_proto.cc:233
const std::vector< VnIpam > & GetVnIpam() const
Definition: vn.h:171
const VnEntry * vn() const
AgentParam * params() const
Definition: agent.h:1218
void ClearState(DBTableBase *tbl_base, ListenerId listener)
Definition: db_entry.cc:73
IpAddress dns_server
Definition: vn.h:33
boost::asio::ip::address_v4 Ip4Address
Definition: address.h:14
void Register(Callback cb)
Definition: gmp_proto.h:147
Definition: vn.h:151
const Ip4Address & primary_ip_addr() const
const bool GetItfStats(const VnEntry *vn, IpAddress gateway, IgmpInfo::IgmpItfStats &stats)
Definition: igmp_proto.cc:265
IgmpProto(Agent *agent, boost::asio::io_context &io)
Definition: igmp_proto.cc:12
VrfEntry * GetVrf() const
Definition: vn.h:170
uint32_t services_queue_limit()
Definition: agent_param.h:417
VmInterface::VmiType vmi_type() const
VnEntry * vn() const
Definition: vrf.h:101
bool igmp_enabled() const
void ClearItfStats(const VnEntry *vn, IpAddress gateway)
Definition: igmp_proto.cc:293
ProtoHandler * AllocProtoHandler(boost::shared_ptr< PktInfo > info, boost::asio::io_context &io)
Definition: igmp_proto.cc:52
void IgmpProtoInit(void)
Definition: igmp_proto.cc:22
DBTablePartBase * get_table_partition() const
Definition: db_entry.cc:115
const IgmpInfo::IgmpItfStats & GetItfStats() const
Definition: igmp_proto.h:92
DBTableBase::ListenerId vn_listener_id()
Definition: igmp_proto.cc:156
const std::string & fabric_policy_vrf_name() const
Definition: agent.h:908