81d83621212a526a2a2668f5885504be625799c6
[vpp.git] / src / vpp-api / vom / bridge_domain.cpp
1 /*
2  * Copyright (c) 2017 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include "vom/bridge_domain.hpp"
17 #include "vom/bridge_domain_cmds.hpp"
18 #include "vom/interface.hpp"
19 #include "vom/l2_binding.hpp"
20
21 namespace VOM {
22
23 const bridge_domain::learning_mode_t bridge_domain::learning_mode_t::ON(1,
24                                                                         "on");
25 const bridge_domain::learning_mode_t bridge_domain::learning_mode_t::OFF(0,
26                                                                          "off");
27
28 bridge_domain::learning_mode_t::learning_mode_t(int v, const std::string& s)
29   : enum_base<bridge_domain::learning_mode_t>(v, s)
30 {
31 }
32
33 /**
34  * A DB of al the interfaces, key on the name
35  */
36 singular_db<uint32_t, bridge_domain> bridge_domain::m_db;
37
38 bridge_domain::event_handler bridge_domain::m_evh;
39
40 /**
41  * Construct a new object matching the desried state
42  */
43 bridge_domain::bridge_domain(uint32_t id, const learning_mode_t& lmode)
44   : m_id(id)
45   , m_learning_mode(lmode)
46 {
47 }
48
49 bridge_domain::bridge_domain(const bridge_domain& o)
50   : m_id(o.m_id)
51   , m_learning_mode(o.m_learning_mode)
52 {
53 }
54
55 uint32_t
56 bridge_domain::id() const
57 {
58   return (m_id.data());
59 }
60
61 void
62 bridge_domain::sweep()
63 {
64   if (rc_t::OK == m_id.rc()) {
65     HW::enqueue(new bridge_domain_cmds::delete_cmd(m_id));
66   }
67   HW::write();
68 }
69
70 void
71 bridge_domain::replay()
72 {
73   if (rc_t::OK == m_id.rc()) {
74     HW::enqueue(new bridge_domain_cmds::create_cmd(m_id, m_learning_mode));
75   }
76 }
77
78 bridge_domain::~bridge_domain()
79 {
80   sweep();
81
82   // not in the DB anymore.
83   m_db.release(m_id.data(), this);
84 }
85
86 std::string
87 bridge_domain::to_string() const
88 {
89   std::ostringstream s;
90   s << "bridge-domain:[" << m_id.to_string() << "]";
91
92   return (s.str());
93 }
94
95 std::shared_ptr<bridge_domain>
96 bridge_domain::find(uint32_t id)
97 {
98   /*
99  * Loop throught the entire map looking for matching interface.
100  * not the most efficient algorithm, but it will do for now. The
101  * number of L3 configs is low and this is only called during bootup
102  */
103   std::shared_ptr<bridge_domain> bd;
104
105   auto it = m_db.cbegin();
106
107   while (it != m_db.cend()) {
108     /*
109  * The key in the DB is a pair of the interface's name and prefix.
110  * If the keys match, save the L3-config
111  */
112     auto key = it->first;
113
114     if (id == key) {
115       bd = it->second.lock();
116       break;
117     }
118
119     ++it;
120   }
121
122   return (bd);
123 }
124
125 void
126 bridge_domain::update(const bridge_domain& desired)
127 {
128   /*
129  * the desired state is always that the interface should be created
130  */
131   if (rc_t::OK != m_id.rc()) {
132     HW::enqueue(new bridge_domain_cmds::create_cmd(m_id, m_learning_mode));
133   }
134 }
135
136 std::shared_ptr<bridge_domain>
137 bridge_domain::find_or_add(const bridge_domain& temp)
138 {
139   return (m_db.find_or_add(temp.m_id.data(), temp));
140 }
141
142 std::shared_ptr<bridge_domain>
143 bridge_domain::singular() const
144 {
145   return find_or_add(*this);
146 }
147
148 void
149 bridge_domain::dump(std::ostream& os)
150 {
151   m_db.dump(os);
152 }
153
154 void
155 bridge_domain::event_handler::handle_populate(const client_db::key_t& key)
156 {
157   /*
158  * dump VPP Bridge domains
159  */
160   std::shared_ptr<bridge_domain_cmds::dump_cmd> cmd(
161     new bridge_domain_cmds::dump_cmd());
162
163   HW::enqueue(cmd);
164   HW::write();
165
166   for (auto& record : *cmd) {
167     auto& payload = record.get_payload();
168
169     bridge_domain bd(payload.bd_id);
170
171     VOM_LOG(log_level_t::DEBUG) << "dump: " << bd.to_string();
172
173     /*
174  * Write each of the discovered interfaces into the OM,
175  * but disable the HW Command q whilst we do, so that no
176  * commands are sent to VPP
177  */
178     OM::commit(key, bd);
179
180     /**
181  * For each interface in the BD construct an l2_binding
182  */
183     for (unsigned int ii = 0; ii < payload.n_sw_ifs; ii++) {
184       std::shared_ptr<interface> itf =
185         interface::find(payload.sw_if_details[ii].sw_if_index);
186       l2_binding l2(*itf, bd);
187       OM::commit(key, l2);
188     }
189   }
190 }
191
192 bridge_domain::event_handler::event_handler()
193 {
194   OM::register_listener(this);
195   inspect::register_handler({ "bd", "bridge" }, "Bridge Domains", this);
196 }
197
198 void
199 bridge_domain::event_handler::handle_replay()
200 {
201   m_db.replay();
202 }
203
204 dependency_t
205 bridge_domain::event_handler::order() const
206 {
207   return (dependency_t::TABLE);
208 }
209
210 void
211 bridge_domain::event_handler::show(std::ostream& os)
212 {
213   m_db.dump(os);
214 }
215 }
216
217 /*
218  * fd.io coding-style-patch-verification: ON
219  *
220  * Local Variables:
221  * eval: (c-set-style "mozilla")
222  * End:
223  */