vxlan: vxlan/vxlan.api API cleanup
[vpp.git] / extras / vom / vom / l2_xconnect.cpp
1 /*
2  * Copyright (c) 2018 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/l2_xconnect.hpp"
17 #include "vom/l2_vtr_cmds.hpp"
18 #include "vom/l2_xconnect_cmds.hpp"
19 #include "vom/singular_db_funcs.hpp"
20
21 namespace VOM {
22 /**
23  * A DB of all the L2 x-connect Configs
24  */
25 singular_db<l2_xconnect::key_t, l2_xconnect> l2_xconnect::m_db;
26
27 l2_xconnect::event_handler l2_xconnect::m_evh;
28
29 /**
30  * Construct a new object matching the desried state
31  */
32 l2_xconnect::l2_xconnect(const interface& east_itf, const interface& west_itf)
33   : m_east_itf(east_itf.singular())
34   , m_west_itf(west_itf.singular())
35   , m_xconnect_east(0)
36   , m_xconnect_west(0)
37   , m_vtr_op(l2_vtr::option_t::DISABLED, rc_t::UNSET)
38   , m_vtr_op_tag(0)
39 {
40 }
41
42 l2_xconnect::l2_xconnect(const l2_xconnect& o)
43   : m_east_itf(o.m_east_itf)
44   , m_west_itf(o.m_west_itf)
45   , m_xconnect_east(o.m_xconnect_east)
46   , m_xconnect_west(o.m_xconnect_west)
47   , m_vtr_op(o.m_vtr_op)
48   , m_vtr_op_tag(o.m_vtr_op_tag)
49 {
50 }
51
52 const l2_xconnect::key_t
53 l2_xconnect::key() const
54 {
55   if (m_east_itf->name() < m_west_itf->name())
56     return (std::make_pair(m_east_itf->key(), m_west_itf->key()));
57   return (std::make_pair(m_west_itf->key(), m_east_itf->key()));
58 }
59
60 bool
61 l2_xconnect::operator==(const l2_xconnect& l) const
62 {
63   return ((*m_east_itf == *l.m_east_itf) && (*m_west_itf == *l.m_west_itf));
64 }
65
66 std::shared_ptr<l2_xconnect>
67 l2_xconnect::find(const key_t& key)
68 {
69   return (m_db.find(key));
70 }
71
72 void
73 l2_xconnect::sweep()
74 {
75   if (m_xconnect_east && m_xconnect_west &&
76       handle_t::INVALID != m_east_itf->handle() &&
77       handle_t::INVALID != m_west_itf->handle()) {
78     HW::enqueue(new l2_xconnect_cmds::unbind_cmd(
79       m_xconnect_east, m_east_itf->handle(), m_west_itf->handle()));
80     HW::enqueue(new l2_xconnect_cmds::unbind_cmd(
81       m_xconnect_west, m_west_itf->handle(), m_east_itf->handle()));
82   }
83
84   HW::write();
85 }
86
87 void
88 l2_xconnect::replay()
89 {
90   if (m_xconnect_east && m_xconnect_west &&
91       handle_t::INVALID != m_east_itf->handle() &&
92       handle_t::INVALID != m_west_itf->handle()) {
93     HW::enqueue(new l2_xconnect_cmds::bind_cmd(
94       m_xconnect_east, m_east_itf->handle(), m_west_itf->handle()));
95     HW::enqueue(new l2_xconnect_cmds::bind_cmd(
96       m_xconnect_west, m_west_itf->handle(), m_east_itf->handle()));
97   }
98
99   if (m_vtr_op && handle_t::INVALID != m_east_itf->handle()) {
100     HW::enqueue(
101       new l2_vtr_cmds::set_cmd(m_vtr_op, m_east_itf->handle(), m_vtr_op_tag));
102   }
103 }
104
105 l2_xconnect::~l2_xconnect()
106 {
107   sweep();
108
109   // not in the DB anymore.
110   m_db.release(key(), this);
111 }
112
113 std::string
114 l2_xconnect::to_string() const
115 {
116   std::ostringstream s;
117   s << "L2-xconnect:[" << m_east_itf->to_string() << " "
118     << m_west_itf->to_string() << " " << m_xconnect_east.to_string() << " "
119     << m_xconnect_west.to_string() << "]";
120
121   return (s.str());
122 }
123
124 void
125 l2_xconnect::set(const l2_vtr::option_t& op, uint16_t tag)
126 {
127   assert(rc_t::UNSET == m_vtr_op.rc());
128   m_vtr_op.set(rc_t::NOOP);
129   m_vtr_op.update(op);
130   m_vtr_op_tag = tag;
131 }
132
133 void
134 l2_xconnect::update(const l2_xconnect& desired)
135 {
136   /*
137    * the desired state is always that the interface should be created
138    */
139   if (rc_t::OK != m_xconnect_east.rc() && rc_t::OK != m_xconnect_west.rc()) {
140     HW::enqueue(new l2_xconnect_cmds::bind_cmd(
141       m_xconnect_east, m_east_itf->handle(), m_west_itf->handle()));
142     HW::enqueue(new l2_xconnect_cmds::bind_cmd(
143       m_xconnect_west, m_west_itf->handle(), m_east_itf->handle()));
144   }
145
146   /*
147    * set the VTR operation if request
148    */
149   if (m_vtr_op.update(desired.m_vtr_op)) {
150     HW::enqueue(
151       new l2_vtr_cmds::set_cmd(m_vtr_op, m_east_itf->handle(), m_vtr_op_tag));
152   }
153 }
154
155 std::shared_ptr<l2_xconnect>
156 l2_xconnect::find_or_add(const l2_xconnect& temp)
157 {
158   return (m_db.find_or_add(temp.key(), temp));
159 }
160
161 std::shared_ptr<l2_xconnect>
162 l2_xconnect::singular() const
163 {
164   return find_or_add(*this);
165 }
166
167 void
168 l2_xconnect::dump(std::ostream& os)
169 {
170   db_dump(m_db, os);
171 }
172
173 l2_xconnect::event_handler::event_handler()
174 {
175   OM::register_listener(this);
176   inspect::register_handler({ "l2-xconnect" }, "L2 xconnects", this);
177 }
178
179 void
180 l2_xconnect::event_handler::handle_replay()
181 {
182   m_db.replay();
183 }
184
185 void
186 l2_xconnect::event_handler::handle_populate(const client_db::key_t& key)
187 {
188   /**
189    * This needs to be done here
190    */
191   std::shared_ptr<l2_xconnect_cmds::dump_cmd> cmd =
192     std::make_shared<l2_xconnect_cmds::dump_cmd>();
193
194   HW::enqueue(cmd);
195   HW::write();
196
197   for (auto& x_record : *cmd) {
198     auto& payload = x_record.get_payload();
199
200     VOM_LOG(log_level_t::DEBUG) << "l2-xconnect dump: "
201                                 << " east-itf: " << payload.rx_sw_if_index
202                                 << " west-itf: " << payload.tx_sw_if_index;
203
204     std::shared_ptr<interface> east_itf =
205       interface::find(payload.rx_sw_if_index);
206     std::shared_ptr<interface> west_itf =
207       interface::find(payload.tx_sw_if_index);
208
209     if (east_itf && west_itf) {
210       if (east_itf->name() > west_itf->name())
211         continue;
212       l2_xconnect l2_xc(*east_itf, *west_itf);
213       OM::commit(key, l2_xc);
214     }
215   }
216 }
217
218 dependency_t
219 l2_xconnect::event_handler::order() const
220 {
221   return (dependency_t::BINDING);
222 }
223
224 void
225 l2_xconnect::event_handler::show(std::ostream& os)
226 {
227   db_dump(m_db, os);
228 }
229 }
230
231 /*
232  * fd.io coding-style-patch-verification: ON
233  *
234  * Local Variables:
235  * eval: (c-set-style "mozilla")
236  * End:
237  */