Line data Source code
1 : /*
2 : * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include <boost/uuid/uuid_io.hpp>
7 : #include <vnc_cfg_types.h>
8 : #include <cmn/agent_cmn.h>
9 :
10 : #include <net/if.h>
11 : #include <ifmap/ifmap_node.h>
12 : #include <cfg/cfg_init.h>
13 : #include <cfg/cfg_listener.h>
14 : #include <oper/agent_sandesh.h>
15 : #include <oper/ifmap_dependency_manager.h>
16 : #include <oper/interface_common.h>
17 : #include <oper/physical_device.h>
18 : #include <oper/nexthop.h>
19 : #include <oper/config_manager.h>
20 :
21 : #include <vector>
22 : #include <string>
23 :
24 : using std::string;
25 :
26 : /////////////////////////////////////////////////////////////////////////////
27 : // PhysicalInterface routines
28 : /////////////////////////////////////////////////////////////////////////////
29 68 : PhysicalInterface::PhysicalInterface(const std::string &name,
30 68 : const boost::uuids::uuid &logical_router_uuid) :
31 0 : Interface(Interface::PHYSICAL, boost::uuids::nil_uuid(), name, NULL, true,
32 : logical_router_uuid),
33 68 : persistent_(false), subtype_(INVALID), physical_device_(NULL) {
34 68 : }
35 :
36 136 : PhysicalInterface::~PhysicalInterface() {
37 136 : }
38 :
39 3 : PhysicalDevice *PhysicalInterface::physical_device() const {
40 3 : return physical_device_.get();
41 : }
42 :
43 0 : string PhysicalInterface::ToString() const {
44 0 : return "PORT <" + name() + ">";
45 : }
46 :
47 156 : bool PhysicalInterface::CmpInterface(const DBEntry &rhs) const {
48 156 : const PhysicalInterface &a = static_cast<const PhysicalInterface &>(rhs);
49 156 : return name() < a.name();
50 : }
51 :
52 9 : DBEntryBase::KeyPtr PhysicalInterface::GetDBRequestKey() const {
53 9 : InterfaceKey *key = new PhysicalInterfaceKey(name());
54 9 : return DBEntryBase::KeyPtr(key);
55 : }
56 :
57 6 : bool PhysicalInterface::OnChange(const InterfaceTable *table,
58 : const PhysicalInterfaceData *data) {
59 6 : bool ret = false;
60 : const PhysicalInterfaceOsOperStateData *osOperStateData =
61 6 : dynamic_cast<const PhysicalInterfaceOsOperStateData *>(data);
62 :
63 6 : if(osOperStateData) {
64 0 : ret = osOperStateData->OnResync(this);
65 : }
66 : else {
67 : // Handle VRF Change
68 6 : VrfKey key(data->vrf_name_);
69 6 : VrfEntry *new_vrf = static_cast<VrfEntry *>
70 6 : (table->agent()->vrf_table()->FindActiveEntry(&key));
71 6 : if (new_vrf != vrf_.get()) {
72 3 : vrf_.reset(new_vrf);
73 3 : ret = true;
74 :
75 : }
76 :
77 : PhysicalDevice *dev =
78 6 : table->agent()->physical_device_table()->Find(data->device_uuid_);
79 6 : if (dev != physical_device_.get()) {
80 2 : physical_device_.reset(dev);
81 2 : ret = true;
82 : }
83 6 : }
84 6 : return ret;
85 : }
86 :
87 : bool
88 0 : PhysicalInterfaceOsOperStateData::OnResync(PhysicalInterface *phy_intf) const
89 : {
90 0 : bool ret = false;
91 0 : if(type_ == PhysicalInterfaceOsOperStateData::VR_FABRIC) {
92 0 : if(phy_intf->os_params_.os_oper_state_ != oper_state_) {
93 0 : phy_intf->os_params_.os_oper_state_ = oper_state_;
94 0 : ret = true;
95 : }
96 0 : } else if(type_ == PhysicalInterfaceOsOperStateData::VR_BOND_SLAVES) {
97 0 : PhysicalInterface::Bond_ChildIntf bondIntf;
98 :
99 0 : bondIntf.intf_name = intf_name;
100 0 : bondIntf.intf_drv_name = intf_drv_name;
101 0 : bondIntf.intf_status = oper_state_;
102 : PhysicalInterface::BondChildIntfMap bond_childIntf_map =
103 0 : phy_intf->getBondChildIntfMap();
104 0 : bond_childIntf_map[intf_name] = bondIntf;
105 0 : phy_intf->setBondChildIntfMap(bond_childIntf_map);
106 0 : ret = true;
107 0 : }
108 :
109 0 : return ret;
110 : }
111 :
112 4 : bool PhysicalInterface::Delete(const DBRequest *req) {
113 4 : flow_key_nh_.reset();
114 4 : InterfaceNH::DeletePhysicalInterfaceNh(name(), mac());
115 4 : return true;
116 : }
117 :
118 0 : std::string PhysicalInterface::GetPhysicalInterfaceName() const {
119 0 : std::size_t pos = name().find_last_of(":");
120 0 : if (pos != string::npos) {
121 0 : return name().substr(pos + 1);
122 : }
123 0 : return name();
124 : }
125 :
126 3 : void PhysicalInterface::PostAdd() {
127 3 : InterfaceNH::CreatePhysicalInterfaceNh(name(), mac());
128 :
129 3 : InterfaceTable *table = static_cast<InterfaceTable *>(get_table());
130 3 : Agent *agent = table->agent();
131 :
132 3 : InterfaceNHKey key(new PhysicalInterfaceKey(name()), false, InterfaceNHFlags::INET4, mac());
133 : flow_key_nh_ = static_cast<InterfaceNH *>
134 3 : (agent->nexthop_table()->FindActiveEntry(&key));
135 3 : assert(flow_key_nh_);
136 :
137 :
138 3 : if (table->agent()->test_mode()) {
139 3 : return;
140 : }
141 :
142 0 : std::string interface_name = name();
143 : // Interfaces in VMWARE mode and having remote VMs
144 : // must be put into promiscuous mode
145 0 : if (subtype_ != VMWARE) {
146 0 : if (!table->agent()->server_gateway_mode() ||
147 0 : subtype_ == PhysicalInterface::FABRIC) {
148 0 : return;
149 : } else {
150 0 : interface_name = GetPhysicalInterfaceName();
151 : }
152 : }
153 :
154 0 : int fd = socket(AF_LOCAL, SOCK_STREAM, 0);
155 0 : assert(fd >= 0);
156 :
157 : struct ifreq ifr;
158 0 : memset(&ifr, 0, sizeof(ifr));
159 0 : strncpy(ifr.ifr_name, interface_name.c_str(), IF_NAMESIZE-1);
160 :
161 0 : if (ioctl(fd, SIOCGIFFLAGS, (void *)&ifr) < 0) {
162 0 : LOG(ERROR, "Error <" << errno << ": " << strerror(errno) <<
163 : "> setting promiscuous flag for interface <" << interface_name << ">");
164 0 : close(fd);
165 0 : return;
166 : }
167 :
168 0 : ifr.ifr_flags |= IFF_PROMISC;
169 0 : if (ioctl(fd, SIOCSIFFLAGS, (void *)&ifr) < 0) {
170 0 : LOG(ERROR, "Error <" << errno << ": " << strerror(errno) <<
171 : "> setting promiscuous flag for interface <" << interface_name << ">");
172 0 : close(fd);
173 0 : return;
174 : }
175 :
176 0 : close(fd);
177 :
178 3 : }
179 :
180 : /////////////////////////////////////////////////////////////////////////////
181 : // PhysicalInterfaceKey routines
182 : /////////////////////////////////////////////////////////////////////////////
183 63 : PhysicalInterfaceKey::PhysicalInterfaceKey(const std::string &name) :
184 : InterfaceKey(AgentKey::ADD_DEL_CHANGE, Interface::PHYSICAL,
185 63 : boost::uuids::nil_uuid(), name, false) {
186 63 : }
187 :
188 90 : PhysicalInterfaceKey::~PhysicalInterfaceKey() {
189 90 : }
190 :
191 65 : Interface *PhysicalInterfaceKey::AllocEntry(const InterfaceTable *table) const {
192 65 : return new PhysicalInterface(name_, boost::uuids::nil_uuid());
193 : }
194 :
195 3 : Interface *PhysicalInterfaceKey::AllocEntry(const InterfaceTable *table,
196 : const InterfaceData *data) const {
197 3 : PhysicalInterface *intf = new PhysicalInterface(name_,
198 3 : data->logical_router_uuid_);
199 3 : const PhysicalInterfaceData *phy_data =
200 : static_cast<const PhysicalInterfaceData *>(data);
201 3 : intf->encap_type_ = phy_data->encap_type_;
202 3 : intf->no_arp_ = phy_data->no_arp_;
203 3 : intf->subtype_ = phy_data->subtype_;
204 3 : intf->display_name_ = phy_data->display_name_;
205 3 : if (intf->subtype_ == PhysicalInterface::VMWARE ||
206 3 : intf->subtype_ == PhysicalInterface::CONFIG) {
207 1 : intf->persistent_ = true;
208 : }
209 :
210 3 : intf->OnChange(table, phy_data);
211 3 : return intf;
212 : }
213 :
214 0 : InterfaceKey *PhysicalInterfaceKey::Clone() const {
215 0 : return new PhysicalInterfaceKey(name_);
216 : }
217 :
218 : /////////////////////////////////////////////////////////////////////////////
219 : // PhysicalInterfaceData routines
220 : /////////////////////////////////////////////////////////////////////////////
221 6 : PhysicalInterfaceData::PhysicalInterfaceData(Agent *agent, IFMapNode *node,
222 : const string &vrf_name,
223 : PhysicalInterface::SubType subtype,
224 : PhysicalInterface::EncapType encap,
225 : bool no_arp,
226 : const boost::uuids::uuid &device_uuid,
227 : const string &display_name,
228 : const Ip4Address &ip,
229 6 : Interface::Transport transport) :
230 6 : InterfaceData(agent, node, transport), subtype_(subtype), encap_type_(encap),
231 6 : no_arp_(no_arp), device_uuid_(device_uuid), display_name_(display_name),
232 6 : ip_(ip) {
233 6 : EthInit(vrf_name);
234 6 : }
235 :
236 : /////////////////////////////////////////////////////////////////////////////
237 : // Config handling routines
238 : /////////////////////////////////////////////////////////////////////////////
239 6 : static PhysicalInterfaceKey *BuildKey(const std::string &name) {
240 6 : return new PhysicalInterfaceKey(name);
241 : }
242 :
243 9 : bool InterfaceTable::PhysicalInterfaceIFNodeToReq(IFMapNode *node,
244 : DBRequest &req,
245 : const boost::uuids::uuid &u) {
246 :
247 : // Enqueue request to config-manager if add/change
248 16 : if ((req.oper != DBRequest::DB_ENTRY_DELETE) &&
249 7 : (node->IsDeleted() == false)) {
250 7 : agent()->config_manager()->AddPhysicalInterfaceNode(node);
251 7 : return false;
252 : }
253 :
254 : autogen::PhysicalInterface *port =
255 2 : static_cast <autogen::PhysicalInterface *>(node->GetObject());
256 2 : assert(port);
257 :
258 : // Get the physical-router from FQDN
259 2 : string device = "";
260 2 : vector<string> elements;
261 2 : split(elements, node->name(), boost::is_any_of(":"), boost::token_compress_on);
262 2 : if (elements.size() == 3) {
263 0 : device = elements[1];
264 : }
265 :
266 2 : if (elements.size() == 3 && device != agent()->agent_name()) {
267 0 : if (RemotePhysicalInterfaceIFNodeToReq(node, req, u)) {
268 0 : Enqueue(&req);
269 : }
270 0 : return false;
271 : }
272 :
273 2 : req.key.reset(BuildKey(node->name()));
274 2 : req.oper = DBRequest::DB_ENTRY_DELETE;
275 2 : return true;
276 2 : }
277 :
278 4 : bool InterfaceTable::PhysicalInterfaceProcessConfig(IFMapNode *node,
279 : DBRequest &req, const boost::uuids::uuid &u) {
280 :
281 4 : if (node->IsDeleted()) {
282 0 : return false;
283 : }
284 :
285 : autogen::PhysicalInterface *port =
286 4 : static_cast <autogen::PhysicalInterface *>(node->GetObject());
287 4 : assert(port);
288 :
289 : // Get the physical-router from FQDN
290 4 : string device = "";
291 4 : vector<string> elements;
292 4 : split(elements, node->name(), boost::is_any_of(":"), boost::token_compress_on);
293 4 : if (elements.size() == 3) {
294 0 : device = elements[1];
295 : }
296 :
297 : // If physical-router does not match agent_name, treat as remote interface
298 4 : if (elements.size() == 3 && device != agent()->agent_name()) {
299 0 : return RemotePhysicalInterfaceIFNodeToReq(node, req, u);
300 : }
301 :
302 4 : req.key.reset(BuildKey(node->name()));
303 :
304 4 : boost::uuids::uuid dev_uuid = boost::uuids::nil_uuid();
305 : // Find link with physical-router adjacency
306 4 : IFMapNode *adj_node = NULL;
307 4 : adj_node = agent()->config_manager()->FindAdjacentIFMapNode(node,
308 : "physical-router");
309 4 : if (adj_node) {
310 : autogen::PhysicalRouter *router =
311 3 : static_cast<autogen::PhysicalRouter *>(adj_node->GetObject());
312 3 : autogen::IdPermsType id_perms = router->id_perms();
313 3 : CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong,
314 : dev_uuid);
315 3 : }
316 4 : req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
317 8 : req.data.reset(new PhysicalInterfaceData(agent(), node,
318 4 : agent()->fabric_vrf_name(),
319 : PhysicalInterface::CONFIG,
320 : PhysicalInterface::ETHERNET,
321 : false, dev_uuid,
322 4 : port->display_name(),
323 4 : Ip4Address(0),
324 4 : Interface::TRANSPORT_ETHERNET));
325 4 : pi_ifnode_to_req_++;
326 4 : Enqueue(&req);
327 4 : return false;
328 4 : }
329 :
330 : /////////////////////////////////////////////////////////////////////////////
331 : // Utility methods
332 : /////////////////////////////////////////////////////////////////////////////
333 : // Enqueue DBRequest to create a Host Interface
334 0 : void PhysicalInterface::CreateReq(InterfaceTable *table, const string &ifname,
335 : const string &vrf_name, SubType subtype,
336 : EncapType encap, bool no_arp,
337 : const boost::uuids::uuid &device_uuid,
338 : const Ip4Address &ip,
339 : Interface::Transport transport) {
340 0 : DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
341 0 : req.key.reset(new PhysicalInterfaceKey(ifname));
342 0 : req.data.reset(new PhysicalInterfaceData(NULL, NULL, vrf_name, subtype,
343 : encap, no_arp, device_uuid,
344 0 : ifname, ip, transport));
345 0 : table->Enqueue(&req);
346 0 : }
347 :
348 2 : void PhysicalInterface::Create(InterfaceTable *table, const string &ifname,
349 : const string &vrf_name, SubType subtype,
350 : EncapType encap, bool no_arp,
351 : const boost::uuids::uuid &device_uuid,
352 : const Ip4Address &ip,
353 : Interface::Transport transport) {
354 2 : DBRequest req(DBRequest::DB_ENTRY_ADD_CHANGE);
355 2 : req.key.reset(new PhysicalInterfaceKey(ifname));
356 2 : req.data.reset(new PhysicalInterfaceData(NULL, NULL, vrf_name, subtype,
357 : encap, no_arp, device_uuid,
358 2 : ifname, ip, transport));
359 2 : table->Process(req);
360 2 : }
361 :
362 : // Enqueue DBRequest to delete a Host Interface
363 0 : void PhysicalInterface::DeleteReq(InterfaceTable *table, const string &ifname) {
364 0 : DBRequest req(DBRequest::DB_ENTRY_DELETE);
365 0 : req.key.reset(new PhysicalInterfaceKey(ifname));
366 0 : req.data.reset(NULL);
367 0 : table->Enqueue(&req);
368 0 : }
369 :
370 0 : void PhysicalInterface::Delete(InterfaceTable *table, const string &ifname) {
371 0 : DBRequest req(DBRequest::DB_ENTRY_DELETE);
372 0 : req.key.reset(new PhysicalInterfaceKey(ifname));
373 0 : req.data.reset(NULL);
374 0 : table->Process(req);
375 0 : }
|