Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 : #include <iostream>
6 : #include <sys/types.h>
7 : #include <sys/stat.h>
8 : #include <unistd.h>
9 :
10 : #include <sys/stat.h>
11 :
12 : #include <boost/property_tree/ini_parser.hpp>
13 : #include <boost/algorithm/string.hpp>
14 : #include <boost/foreach.hpp>
15 : #include <vector>
16 : #include <pugixml/pugixml.hpp>
17 : #include <base/logging.h>
18 :
19 : #include <cmn/agent_cmn.h>
20 : #include <init/agent_param.h>
21 : #include <cfg/cfg_init.h>
22 : #include <vgw/cfg_vgw.h>
23 : #include <oper/interface_common.h>
24 : #include <vgw/vgw.h>
25 :
26 : using namespace std;
27 : using namespace boost::property_tree;
28 : using namespace boost::uuids;
29 : using boost::optional;
30 :
31 : // Config init. Read the "gateway" node and add the configuration
32 : // Handle only one gateway config for now
33 2 : void VirtualGatewayConfigTable::InitFromConfig
34 : (const boost::property_tree::ptree pt) {
35 2 : const std::string gw_str = "GATEWAY";
36 :
37 6 : BOOST_FOREACH(const ptree::value_type §ion, pt) {
38 2 : if (section.first.compare(0, gw_str.size(), gw_str) != 0) {
39 2 : continue;
40 : }
41 0 : string vrf = "";
42 0 : string interfacestr = "";
43 0 : VirtualGatewayConfig::SubnetList subnets;
44 0 : VirtualGatewayConfig::SubnetList routes;
45 0 : BOOST_FOREACH(const ptree::value_type &key, section.second) {
46 0 : if (key.first.compare("routing_instance") == 0) {
47 0 : vrf = key.second.get_value<string>();
48 : }
49 0 : if (key.first.compare("interface") == 0) {
50 0 : interfacestr = key.second.get_value<string>();
51 : }
52 0 : if (key.first.compare("ip_blocks") == 0) {
53 0 : BuildSubnetList(key.second.get_value<string>(), subnets);
54 : }
55 0 : if (key.first.compare("routes") == 0) {
56 0 : BuildSubnetList(key.second.get_value<string>(), routes);
57 : }
58 : }
59 0 : if (vrf == "" || interfacestr == "" || subnets.size() == 0) {
60 0 : LOG(ERROR, "Error in config file. Invalid/incomplete gateway "
61 : "section" << section.first);
62 0 : continue;
63 0 : }
64 :
65 0 : std::sort(subnets.begin(), subnets.end());
66 0 : std::sort(routes.begin(), routes.end());
67 0 : table_.insert(VirtualGatewayConfig(interfacestr, vrf,
68 : subnets, routes, (uint32_t) -1));
69 0 : }
70 4 : return;
71 2 : }
72 :
73 0 : void VirtualGatewayConfigTable::BuildSubnetList
74 : (const string &subnets, VirtualGatewayConfig::SubnetList &results) {
75 0 : Ip4Address addr;
76 : int plen;
77 0 : boost::system::error_code ec;
78 0 : results.clear();
79 0 : if (!subnets.empty()) {
80 0 : vector<string> tokens;
81 0 : boost::split(tokens, subnets, boost::is_any_of(" "));
82 0 : vector<string>::iterator it = tokens.begin();
83 0 : while (it != tokens.end()) {
84 0 : std::string str = *it;
85 0 : boost::algorithm::trim(str);
86 0 : ++it;
87 0 : ec = Ip4PrefixParse(str, &addr, &plen);
88 0 : if (ec.failed() || plen >= 32) {
89 0 : LOG(ERROR, "Error in config file. Invalid gateway "
90 : "ip_block/route " << str);
91 0 : continue;
92 0 : }
93 0 : results.push_back(VirtualGatewayConfig::Subnet(addr, plen));
94 0 : }
95 0 : }
96 0 : }
97 :
98 2 : void VirtualGatewayConfigTable::InitDone(Agent *agent) {
99 2 : agent_ = agent;
100 4 : work_queue_.reset(new WorkQueue<boost::shared_ptr<VirtualGatewayData> >
101 4 : (agent_->task_scheduler()->GetTaskId("db::DBTable"), 0,
102 : boost::bind(&VirtualGatewayConfigTable::ProcessRequest,
103 2 : this, _1)));
104 2 : work_queue_->set_name("VGW");
105 2 : }
106 :
107 0 : void VirtualGatewayConfigTable::Shutdown() {
108 0 : work_queue_->Shutdown();
109 0 : }
110 :
111 0 : void VirtualGatewayConfigTable::Enqueue(
112 : boost::shared_ptr<VirtualGatewayData> request) {
113 0 : work_queue_->Enqueue(request);
114 0 : }
115 :
116 0 : bool VirtualGatewayConfigTable::ProcessRequest(
117 : boost::shared_ptr<VirtualGatewayData> request) {
118 0 : switch(request->message_type_) {
119 0 : case VirtualGatewayData::Add:
120 0 : BOOST_FOREACH(VirtualGatewayInfo &vgw, request->vgw_list_) {
121 0 : AddVgw(vgw, request->version_);
122 : }
123 0 : break;
124 :
125 0 : case VirtualGatewayData::Delete:
126 0 : BOOST_FOREACH(VirtualGatewayInfo &vgw, request->vgw_list_) {
127 0 : DeleteVgw(vgw.interface_name_);
128 : }
129 0 : break;
130 :
131 0 : case VirtualGatewayData::Audit:
132 0 : DeleteAllOldVersionVgw(request->version_);
133 0 : break;
134 :
135 0 : default:
136 0 : assert(0);
137 : }
138 0 : return true;
139 : }
140 :
141 : // Add / modify a virtual gateway
142 0 : bool VirtualGatewayConfigTable::AddVgw(VirtualGatewayInfo &vgw, uint32_t version) {
143 0 : std::sort(vgw.subnets_.begin(), vgw.subnets_.end());
144 0 : std::sort(vgw.routes_.begin(), vgw.routes_.end());
145 0 : Table::iterator it = table_.find(vgw.interface_name_);
146 0 : Interface::Transport transport = Interface::TRANSPORT_ETHERNET;
147 0 : if (agent_->vrouter_on_nic_mode() ||
148 0 : agent_->vrouter_on_host_dpdk()) {
149 0 : transport = Interface::TRANSPORT_PMD;
150 : }
151 0 : if (it == table_.end()) {
152 : // Add new gateway
153 0 : table_.insert(VirtualGatewayConfig(vgw.interface_name_, vgw.vrf_name_,
154 0 : vgw.subnets_, vgw.routes_, version));
155 0 : agent_->vgw()->CreateVrf(vgw.vrf_name_);
156 0 : agent_->vgw()->CreateInterface(vgw.interface_name_, vgw.vrf_name_,
157 : transport);
158 : } else {
159 : // modify existing gateway
160 0 : if (vgw.vrf_name_ != it->vrf_name()) {
161 0 : LOG(DEBUG, "Virtual Gateway : change of vrf is not allowed; " <<
162 : "Interface : " << vgw.interface_name_ << " Old VRF : " <<
163 : it->vrf_name() << " New VRF : " << vgw.vrf_name_);
164 0 : return false;
165 : }
166 0 : VirtualGatewayConfig::SubnetList add_list, del_list;
167 0 : if (FindChange(it->subnets(), vgw.subnets_, add_list, del_list)) {
168 0 : agent_->vgw()->SubnetUpdate(*it, add_list, del_list);
169 0 : it->set_subnets(vgw.subnets_);
170 : }
171 :
172 0 : add_list.clear();
173 0 : del_list.clear();
174 0 : if (FindChange(it->routes(), vgw.routes_, add_list, del_list)) {
175 0 : agent_->vgw()->RouteUpdate(*it, vgw.routes_, add_list, del_list, true);
176 0 : it->set_routes(vgw.routes_);
177 : }
178 0 : it->set_version(version);
179 0 : }
180 0 : return true;
181 : }
182 :
183 : // Delete a virtual gateway
184 0 : bool VirtualGatewayConfigTable::DeleteVgw(const std::string &interface_name) {
185 0 : Table::iterator it = table_.find(interface_name);
186 0 : if (it != table_.end()) {
187 0 : DeleteVgw(it);
188 0 : return true;
189 : }
190 :
191 0 : LOG(DEBUG, "Virtual Gateway delete : interface not present; " <<
192 : "Interface : " << interface_name);
193 0 : return false;
194 : }
195 :
196 0 : void VirtualGatewayConfigTable::DeleteVgw(Table::iterator it) {
197 0 : VirtualGatewayConfig::SubnetList empty_list;
198 0 : agent_->vgw()->SubnetUpdate(*it, empty_list, it->subnets());
199 0 : agent_->vgw()->RouteUpdate(*it, empty_list, empty_list,
200 : it->routes(), false);
201 0 : agent_->vgw()->DeleteInterface(it->interface_name());
202 0 : agent_->vgw()->DeleteVrf(it->vrf_name());
203 0 : table_.erase(it);
204 0 : }
205 :
206 : // delete all entries from previous version
207 0 : void VirtualGatewayConfigTable::DeleteAllOldVersionVgw(uint32_t version) {
208 0 : for (Table::iterator it = table_.begin(); it != table_.end();) {
209 0 : if (it->version() < version) {
210 0 : DeleteVgw(it++);
211 : } else {
212 0 : it++;
213 : }
214 : }
215 0 : }
216 :
217 0 : bool VirtualGatewayConfigTable::FindChange(
218 : const VirtualGatewayConfig::SubnetList &old_subnets,
219 : const VirtualGatewayConfig::SubnetList &new_subnets,
220 : VirtualGatewayConfig::SubnetList &add_list,
221 : VirtualGatewayConfig::SubnetList &del_list) {
222 0 : bool change = false;
223 0 : VirtualGatewayConfig::SubnetList::const_iterator it_old = old_subnets.begin();
224 0 : VirtualGatewayConfig::SubnetList::const_iterator it_new = new_subnets.begin();
225 0 : while (it_old != old_subnets.end() && it_new != new_subnets.end()) {
226 0 : if (*it_old < *it_new) {
227 : // old entry is deleted
228 0 : del_list.push_back(*it_old);
229 0 : change = true;
230 0 : it_old++;
231 0 : } else if (*it_new < *it_old) {
232 : // new entry
233 0 : add_list.push_back(*it_new);
234 0 : change = true;
235 0 : it_new++;
236 : } else {
237 : // no change in entry
238 0 : it_old++;
239 0 : it_new++;
240 : }
241 : }
242 :
243 : // delete remaining old entries
244 0 : for (; it_old != old_subnets.end(); ++it_old) {
245 0 : del_list.push_back(*it_old);
246 0 : change = true;
247 : }
248 :
249 : // add remaining new entries
250 0 : for (; it_new != new_subnets.end(); ++it_new) {
251 0 : add_list.push_back(*it_new);
252 0 : change = true;
253 : }
254 :
255 0 : return change;
256 : }
|