GBP: add allowed ethertypes to contracts
[vpp.git] / extras / vom / vom / l2_binding.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/l2_binding.hpp"
17 #include "vom/l2_binding_cmds.hpp"
18 #include "vom/singular_db_funcs.hpp"
19
20 namespace VOM {
21 /**
22  * A DB of all the L2 Configs
23  */
24 singular_db<l2_binding::key_t, l2_binding> l2_binding::m_db;
25
26 l2_binding::event_handler l2_binding::m_evh;
27
28 /*
29  * Make sure these are in sync with the smae enum in VPP
30  */
31 const l2_binding::l2_vtr_op_t l2_binding::l2_vtr_op_t::L2_VTR_DISABLED(
32   0,
33   "disabled");
34 const l2_binding::l2_vtr_op_t l2_binding::l2_vtr_op_t::L2_VTR_PUSH_1(1,
35                                                                      "push-1");
36 const l2_binding::l2_vtr_op_t l2_binding::l2_vtr_op_t::L2_VTR_PUSH_2(2,
37                                                                      "push-2");
38 const l2_binding::l2_vtr_op_t l2_binding::l2_vtr_op_t::L2_VTR_POP_1(3, "pop-1");
39 const l2_binding::l2_vtr_op_t l2_binding::l2_vtr_op_t::L2_VTR_POP_2(4, "pop-2");
40 const l2_binding::l2_vtr_op_t l2_binding::l2_vtr_op_t::L2_VTR_TRANSLATE_1_1(
41   5,
42   "translate-1-1");
43 const l2_binding::l2_vtr_op_t l2_binding::l2_vtr_op_t::L2_VTR_TRANSLATE_1_2(
44   6,
45   "translate-1-2");
46 const l2_binding::l2_vtr_op_t l2_binding::l2_vtr_op_t::L2_VTR_TRANSLATE_2_1(
47   7,
48   "translate-2-1");
49 const l2_binding::l2_vtr_op_t l2_binding::l2_vtr_op_t::L2_VTR_TRANSLATE_2_2(
50   5,
51   "translate-2-2");
52
53 l2_binding::l2_vtr_op_t::l2_vtr_op_t(int v, const std::string s)
54   : enum_base<l2_binding::l2_vtr_op_t>(v, s)
55 {
56 }
57
58 const l2_binding::l2_port_type_t
59   l2_binding::l2_port_type_t::L2_PORT_TYPE_NORMAL(0, "normal");
60 const l2_binding::l2_port_type_t l2_binding::l2_port_type_t::L2_PORT_TYPE_BVI(
61   1,
62   "bvi");
63 const l2_binding::l2_port_type_t
64   l2_binding::l2_port_type_t::L2_PORT_TYPE_UU_FWD(2, "uu-fwd");
65
66 l2_binding::l2_port_type_t::l2_port_type_t(int v, const std::string s)
67   : enum_base<l2_binding::l2_port_type_t>(v, s)
68 {
69 }
70
71 /**
72  * Construct a new object matching the desried state
73  */
74 l2_binding::l2_binding(const interface& itf, const bridge_domain& bd)
75   : m_itf(itf.singular())
76   , m_bd(bd.singular())
77   , m_port_type(l2_port_type_t::L2_PORT_TYPE_NORMAL)
78   , m_binding(0)
79   , m_vtr_op(l2_vtr_op_t::L2_VTR_DISABLED, rc_t::UNSET)
80   , m_vtr_op_tag(0)
81 {
82   if (interface::type_t::BVI == m_itf->type())
83     m_port_type = l2_port_type_t::L2_PORT_TYPE_BVI;
84 }
85
86 /**
87  * Construct a new object matching the desried state
88  */
89 l2_binding::l2_binding(const interface& itf,
90                        const bridge_domain& bd,
91                        const l2_port_type_t& port_type)
92   : m_itf(itf.singular())
93   , m_bd(bd.singular())
94   , m_port_type(port_type)
95   , m_binding(0)
96   , m_vtr_op(l2_vtr_op_t::L2_VTR_DISABLED, rc_t::UNSET)
97   , m_vtr_op_tag(0)
98 {
99 }
100
101 l2_binding::l2_binding(const l2_binding& o)
102   : m_itf(o.m_itf)
103   , m_bd(o.m_bd)
104   , m_port_type(o.m_port_type)
105   , m_binding(0)
106   , m_vtr_op(o.m_vtr_op)
107   , m_vtr_op_tag(o.m_vtr_op_tag)
108 {
109 }
110
111 const l2_binding::key_t&
112 l2_binding::key() const
113 {
114   return (m_itf->key());
115 }
116
117 bool
118 l2_binding::operator==(const l2_binding& l) const
119 {
120   return ((*m_itf == *l.m_itf) && (*m_bd == *l.m_bd) &&
121           (m_port_type == l.m_port_type));
122 }
123
124 std::shared_ptr<l2_binding>
125 l2_binding::find(const key_t& key)
126 {
127   return (m_db.find(key));
128 }
129
130 void
131 l2_binding::sweep()
132 {
133   if (m_binding && handle_t::INVALID != m_itf->handle()) {
134     HW::enqueue(new l2_binding_cmds::unbind_cmd(m_binding, m_itf->handle(),
135                                                 m_bd->id(), m_port_type));
136   }
137
138   // no need to undo the VTR operation.
139   HW::write();
140 }
141
142 void
143 l2_binding::replay()
144 {
145   if (m_binding && handle_t::INVALID != m_itf->handle()) {
146     HW::enqueue(new l2_binding_cmds::bind_cmd(m_binding, m_itf->handle(),
147                                               m_bd->id(), m_port_type));
148   }
149
150   if (m_vtr_op && handle_t::INVALID != m_itf->handle()) {
151     HW::enqueue(new l2_binding_cmds::set_vtr_op_cmd(m_vtr_op, m_itf->handle(),
152                                                     m_vtr_op_tag));
153   }
154 }
155
156 l2_binding::~l2_binding()
157 {
158   sweep();
159
160   // not in the DB anymore.
161   m_db.release(m_itf->key(), this);
162 }
163
164 std::string
165 l2_binding::to_string() const
166 {
167   std::ostringstream s;
168   s << "L2-binding:[" << m_itf->to_string() << " " << m_bd->to_string() << " "
169     << m_port_type.to_string() << " " << m_binding.to_string() << "]";
170
171   return (s.str());
172 }
173
174 void
175 l2_binding::set(const l2_vtr_op_t& op, uint16_t tag)
176 {
177   assert(rc_t::UNSET == m_vtr_op.rc());
178   m_vtr_op.set(rc_t::NOOP);
179   m_vtr_op.update(op);
180   m_vtr_op_tag = tag;
181 }
182
183 void
184 l2_binding::update(const l2_binding& desired)
185 {
186   /*
187    * the desired state is always that the interface should be created
188    */
189   if (rc_t::OK != m_binding.rc()) {
190     HW::enqueue(new l2_binding_cmds::bind_cmd(m_binding, m_itf->handle(),
191                                               m_bd->id(), m_port_type));
192   } else if (!(*m_bd == *desired.m_bd)) {
193     /*
194      * re-binding to a different BD. do unbind, bind.
195      */
196     HW::enqueue(new l2_binding_cmds::unbind_cmd(m_binding, m_itf->handle(),
197                                                 m_bd->id(), m_port_type));
198     m_bd = desired.m_bd;
199     HW::enqueue(new l2_binding_cmds::bind_cmd(m_binding, m_itf->handle(),
200                                               m_bd->id(), m_port_type));
201   }
202
203   /*
204    * set the VTR operation if request
205    */
206   if (m_vtr_op.update(desired.m_vtr_op)) {
207     HW::enqueue(new l2_binding_cmds::set_vtr_op_cmd(m_vtr_op, m_itf->handle(),
208                                                     m_vtr_op_tag));
209   }
210 }
211
212 std::shared_ptr<l2_binding>
213 l2_binding::find_or_add(const l2_binding& temp)
214 {
215   return (m_db.find_or_add(temp.m_itf->key(), temp));
216 }
217
218 std::shared_ptr<l2_binding>
219 l2_binding::singular() const
220 {
221   return find_or_add(*this);
222 }
223
224 void
225 l2_binding::dump(std::ostream& os)
226 {
227   db_dump(m_db, os);
228 }
229
230 l2_binding::event_handler::event_handler()
231 {
232   OM::register_listener(this);
233   inspect::register_handler({ "l2" }, "L2 bindings", this);
234 }
235
236 void
237 l2_binding::event_handler::handle_replay()
238 {
239   m_db.replay();
240 }
241
242 void
243 l2_binding::event_handler::handle_populate(const client_db::key_t& key)
244 {
245   /**
246    * This is done while populating the bridge-domain
247    */
248 }
249
250 dependency_t
251 l2_binding::event_handler::order() const
252 {
253   return (dependency_t::BINDING);
254 }
255
256 void
257 l2_binding::event_handler::show(std::ostream& os)
258 {
259   db_dump(m_db, os);
260 }
261 }
262
263 /*
264  * fd.io coding-style-patch-verification: ON
265  *
266  * Local Variables:
267  * eval: (c-set-style "mozilla")
268  * End:
269  */