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