blob: 88ac7adf2257e3d04de4a9d937e0ebb678698e8a [file] [log] [blame]
srikanth116e6e82014-08-19 07:22:37 -07001#
2# Copyright (c) 2013 Big Switch Networks, Inc.
3#
4# Licensed under the Eclipse Public License, Version 1.0 (the
5# "License"); you may not use this file except in compliance with the
6# License. You may obtain a copy of the License at
7#
8# http://www.eclipse.org/legal/epl-v10.html
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13# implied. See the License for the specific language governing
14# permissions and limitations under the License.
15#
16
17from django.db import models
18from django.contrib.auth.models import User
19
20from django.forms import ValidationError
21from django.core.validators import MaxValueValidator
22from sdncon.rest.validators import *
23
24import sys # for sys.maxint
25import time
26
27#
28# controller/models.py
29# ------------------------------------------------------------
30#
31# model description of the tables used to configure and
32# view the controller state.
33#
34# these tables are used both by sdnplatform and the rest api.
35# the cli uses the rest api to read and write these tables,
36# while sdnplatform/sdnplatform has a more direct interface to the
37# tables.
38#
39# for the cli, the names of the fields are described in the
40# 'class Rest' section of each of the tables.
41#
42# for sdnplatform the names of fields have a relationship to their
43# type for sdnplatform. If a field is a foreign key, then an '_id'
44# is appended to the name for the same field within sdnplatform. This
45# means if a field is promoted or demoted to/from a foreign key,
46# changes need to be made in the sdnplatform code to use the updated
47# name.
48#
49# Make sure to include the nested Rest class or else they won't be
50# accessible using the REST API.
51
52#
53#
54# ------------------------------------------------------------
55
56def get_timestamp():
57 """
58 For us in models where the method of ordering the row values
59 is based on the order of creation.
60
61 The field is exposed to the rest api so that the value can
62 be queries, and so that the rest api may choose to order the
63 row values using its own strategy by setting the field directly
64 """
65 return int(time.time()*1000000)
66
Srikanth Vavilapalli669ba8a2014-10-16 11:41:19 -070067class Tunnel(models.Model):
68
69 id_max_length = 64
70 #
71 # fields ----------------------------------------
72
73 #
74 # Unique name of the Tunnel
75 #
76 tunnel_id = models.CharField(
77 primary_key = True,
78 verbose_name = 'Tunnel Id',
79 help_text = 'A unique Id for a Tunnel',
80 validators = [ TenantNameValidator() ],
81 max_length = id_max_length)
82
83 path_seq = models.CharField(
84 verbose_name = 'Path Sequence',
85 help_text = 'List of path identifiers: nodes or adjacencies',
86 blank = True,
87 null = True,
88 max_length = 500)
89
90 #
91 # end fields ----------------------------------------
92
93 def __unicode__ (self):
94 return self.tunnel_id
95
Srikanth Vavilapalli669ba8a2014-10-16 11:41:19 -070096 def delete(self):
97 super(Tunnel, self).delete()
98 class Rest:
99 NAME = 'tunnel-config'
100 FIELD_INFO = (
101 {'name': 'tunnel_id', 'rest_name': 'tunnel-id'},
102 {'name': 'path_seq', 'rest_name': 'path-seq'},
103 )
104
Srikanth Vavilapalli79d87a12014-10-21 21:02:01 -0700105class Policy(models.Model):
Srikanth Vavilapallifc6891c2014-10-19 20:46:17 -0700106
107 id_max_length = 64
108 #
109 # fields ----------------------------------------
110
111 #
112 # Unique name of the Tunnel
113 #
114 sr_policy_id = models.CharField(
115 primary_key = True,
116 verbose_name = 'SR Policy Id',
117 help_text = 'A unique Id for a SR Policy',
118 validators = [ TenantNameValidator() ],
119 max_length = id_max_length)
120
Srikanth Vavilapalli79d87a12014-10-21 21:02:01 -0700121 sr_policy_type = models.CharField(
122 verbose_name = 'SR Policy Type',
123 help_text = 'Type of SR Policy',
124 validators = [ TenantNameValidator() ],
125 max_length = id_max_length)
Srikanth Vavilapallifc6891c2014-10-19 20:46:17 -0700126 #
127 # end fields ----------------------------------------
128
129 def __unicode__ (self):
Srikanth Vavilapalli79d87a12014-10-21 21:02:01 -0700130 return self.sr_policy_id
Srikanth Vavilapallifc6891c2014-10-19 20:46:17 -0700131
Srikanth Vavilapallifc6891c2014-10-19 20:46:17 -0700132 def delete(self):
Srikanth Vavilapalli79d87a12014-10-21 21:02:01 -0700133 super(Policy, self).delete()
134
Srikanth Vavilapallifc6891c2014-10-19 20:46:17 -0700135 class Rest:
136 NAME = 'policy-config'
137 FIELD_INFO = (
138 {'name': 'sr_policy_id', 'rest_name': 'policy-id'},
Srikanth Vavilapalli79d87a12014-10-21 21:02:01 -0700139 {'name': 'sr_policy_type', 'rest_name': 'policy-type'},
Srikanth Vavilapallifc6891c2014-10-19 20:46:17 -0700140 )
141
srikanth116e6e82014-08-19 07:22:37 -0700142#
143# ------------------------------------------------------------
144
145class Feature(models.Model):
146
147 #
148 # fields ----------------------------------------
149
150 id = models.CharField(
151 primary_key=True,
152 verbose_name='feature',
153 default='feature',
154 max_length=16)
155
156 netvirt_feature = models.BooleanField(
157 verbose_name='Network virtualization Feature Enabled',
158 help_text='Enable network virtualization feature by setting to true',
159 default=True
160 )
161
162 static_flow_pusher_feature = models.BooleanField(
163 verbose_name='Static Flow Pusher Feature Enabled',
164 help_text='Enable Static Flow Pusher feature by setting to true',
165 default=True
166 )
167
168 performance_monitor_feature = models.BooleanField(
169 verbose_name='Performance Monitor',
170 help_text="Enable performance monitoring feature by setting to true",
171 default=False
172 )
173
174 #
175 # end fields ----------------------------------------
176
177 def __unicode__(self):
178 return "%s" % (self.id,)
179
180 def validate_unique(self, exclude = None):
181 if self.id != 'feature':
182 raise ValidationError("Only single feature record exists")
183
184 class Rest:
185 NAME = 'feature'
186 FIELD_INFO = (
187 {'name': 'netvirt_feature', 'rest_name': 'netvirt-feature'},
188 {'name': 'static_flow_pusher_feature', 'rest_name': 'static-flow-pusher-feature'},
189 {'name': 'performance_monitor_feature','rest_name': 'performance-monitor-feature'},
190 )
191
Srikanth Vavilapalli669ba8a2014-10-16 11:41:19 -0700192"""
srikanth116e6e82014-08-19 07:22:37 -0700193#
194# ------------------------------------------------------------
195
196class GlobalConfig(models.Model):
197 #
198 # fields ----------------------------------------
199
200 name = models.CharField(
201 primary_key=True,
202 verbose_name='Global Config Name',
203 help_text="Unique name for the global config; it's a singleton, "
204 "so, by convention, the name should always be \"global\"",
205 default='global',
206 max_length=16)
207
208 cluster_name = models.CharField(
209 verbose_name='Cluster Name',
210 help_text='Name for the cluster',
211 default='SDNCluster',
212 max_length=256)
213
214 cluster_number = models.IntegerField(
215 verbose_name='Cluster Number',
216 help_text='Small integral (1-255) identifier for the cluster',
217 default=0)
218
219 ha_enabled = models.BooleanField(
220 verbose_name='High Availability (HA) Enabled',
221 help_text='Is high availability (HA) enabled',
222 default=False)
223
224 #
225 # end fields ----------------------------------------
226
227 class Rest:
228 NAME = 'global-config'
229 FIELD_INFO = (
230 {'name': 'cluster_name', 'rest_name': 'cluster-name'},
231 {'name': 'cluster_number', 'rest_name': 'cluster-number'},
232 {'name': 'ha_enabled', 'rest_name': 'ha-enabled'},
233 )
234
235#
236# ------------------------------------------------------------
237
238class TopologyConfig(models.Model):
239 #
240 # fields ----------------------------------------
241
242 id = models.CharField(
243 primary_key=True,
244 verbose_name='topology',
245 default='topology',
246 max_length=16)
247
248
249 autoportfast = models.BooleanField(
250 verbose_name='Auto PortFast',
251 help_text='Suppress sending LLDPs on fast ports.',
252 default=True
253 )
254
255 #
256 # end fields ----------------------------------------
257
258 def __unicode__(self):
259 return "%s" % (self.id,)
260
261 def validate_unique(self, exclude = None):
262 if self.id != 'topology':
263 raise ValidationError("Only single topology record exists")
264
265 class Rest:
266 NAME = 'topology-config'
267 FIELD_INFO = (
268 )
269
270
271#
272# ------------------------------------------------------------
273
274class ForwardingConfig(models.Model):
275 #
276 # fields ----------------------------------------
277
278 id = models.CharField(
279 primary_key=True,
280 verbose_name='forwarding',
281 default='forwarding',
282 max_length=16)
283
284 access_priority = models.IntegerField(
285 verbose_name='Access Flow Priority',
286 help_text='Priority for flows created by forwarding on access switches',
287 validators=[ RangeValidator(0,2**15-1) ],
288 default=10)
289
290 core_priority = models.IntegerField(
291 verbose_name='Core Flow Priority',
292 help_text='Priority for flows created by forwarding on core switches',
293 validators=[ RangeValidator(0,2**15-1) ],
294 default=20)
295
296 #
297 # end fields ----------------------------------------
298
299 def __unicode__(self):
300 return "%s" % (self.id,)
301
302 def validate_unique(self, exclude = None):
303 if self.id != 'forwarding':
304 raise ValidationError(
305 "Only a single forwarding configuration record is allowed"
306 )
307
308 class Rest:
309 NAME = 'forwarding-config'
310 FIELD_INFO = (
311 {'name': 'access_priority', 'rest_name': 'access-priority'},
312 {'name': 'core_priority', 'rest_name': 'core-priority'},
313 )
Srikanth Vavilapalli22e58e92014-10-16 14:04:48 -0700314"""
srikanth116e6e82014-08-19 07:22:37 -0700315#
316# ------------------------------------------------------------
srikanth116e6e82014-08-19 07:22:37 -0700317class Controller(models.Model):
318 #
319 # fields ----------------------------------------
320 #
321 # Note: This model should only contain config state for the controller VM,
322 # not any operational state.
323 #
324 # Note: The convention used to be that the controller ID was
325 # the IP address and port that the OpenFlow controller was listening
326 # on. In practice SDNPlatform listened on all interfaces and it's logic
327 # for determining its real IP address was unreliable, so it was
328 # changed/simplified to just always use "localhost" for the
329 # IP address. So the controller ID was pretty much always
330 # "localhost:6633". The use of "controller here caused some
331 # confusion about whether "controller" meant the
332 # OpenFlow controller (i.e. SDNPlatform/SDNPlatform) vs. the controller VM.
333 # In the old controller model most/all of the settings concerned the
334 # OpenFlow controller not the VM>
335 # Most of the settings we now want to associate with the controller are
336 # controller VM settings (e.g. IP address, DNS, time zone) and not
337 # OpenFlow controller settings. So we're repurposing the Controller
338 # model to be the controller VM config state and not the OpenFlow
339 # controller discovered state (which was sort of broken to begin with).
340 # Currently (as of 10/2011), since we only support single node operation
341 # the controller ID is hard-coded to be localhost (probably should be
342 # something different, e.g. "default", because localhost implies a
343 # an interface which is really something separate), but eventually for
344 # multi-node operation we'll need to have unique ids for each controller
345 # node in the cluster. The easiest way would be to have the user enter
346 # something at first time config. Or possibly we could do something
347 # with GUIDs. Needs more thought...
348 id = models.CharField(
349 primary_key=True,
350 verbose_name='Controller ID',
351 help_text='Unique identifier string for the controller node',
352 validators=[ validate_controller_id ],
353 max_length=256)
354
355 status = models.CharField(
356 verbose_name='Status',
357 help_text='cluster status of node',
358 max_length=256,
359 default='Provisioned',
360 )
361
362 domain_lookups_enabled = models.BooleanField(
363 verbose_name='Domain Lookups Enabled',
364 help_text='If domain lookups are enabled (default is True)',
365 default=True
366 )
367
368 domain_name = models.CharField(
369 verbose_name='Domain Name',
370 help_text='Domain name of the network',
371 max_length=256,
372 validators=[ DomainNameValidator() ],
373 default='',
374 blank=True)
375
376 default_gateway = models.CharField(
377 verbose_name='Default Gateway',
378 help_text='Default gateway',
379 max_length=256,
380 validators=[ IpValidator() ],
381 default='',
382 blank=True)
383
384 ntp_server = models.CharField(
385 verbose_name='NTP Server',
386 help_text='NTP server',
387 max_length=256,
388 validators=[ IpOrDomainNameValidator() ],
389 default='',
390 blank=True,
391 null=True)
392
393 time_zone = models.CharField(
394 verbose_name='Time Zone',
395 help_text='Time zone (e.g. America/Los_Angeles)',
396 max_length=256,
397 validators=[ TimeZoneValidator() ],
398 default='UTC')
399
400 logging_enabled = models.BooleanField(
401 verbose_name='Logging Enabled',
402 help_text='Logging enabled',
403 default=False
404 )
405
406 logging_server = models.CharField(
407 verbose_name='Logging Server',
408 help_text='Logging server',
409 max_length=256,
410 validators=[ IpOrDomainNameValidator() ],
411 default='',
412 blank=True,
413 null=True)
414
415 logging_level = models.CharField(
416 verbose_name='Logging Level',
417 help_text='Logging level',
418 max_length=16,
419 validators=[ EnumerationValidator(('emerg', 'alert', 'crit', 'err',
420 'warning', 'notice', 'info', 'debug', '0', '1', '2', '3', '4',
421 '5', '6', '7'))],
422 default='notice'
423 )
424
425 # IOS let's you specify the domain name(s) of the network in two
426 # ways. You can specify a single domain name with the "ip domain name <domain-name>"
427 # command. You can specify multiple domain names with multiple
428 # "ip domain list <domain-name>" commands. The domain names specified with
429 # "ip domain list" commands take precedence over the domain name specified with
430 # the "ip domain name" command, so the single "ip domain name" is only
431 # used if the domain name list is unspecified/empty/null. Kind of messy, but
432 # if we want to emulate IOS behavior I think we'll need to represent that in the
433 # model. But to simplify things for now we'll just support the single domain name.
434
435 #domain_name_list = models.TextField(
436 # verbose_name='Domain Name List',
437 # help_text='List of domain names for the network, one per line',
438 # null=True
439 # )
440
441 #
442 # end fields ----------------------------------------
443
444 def __unicode__(self):
445 return "%s" % (self.id,)
446
447 class Rest:
448 NAME = 'controller-node'
449 FIELD_INFO = (
450 {'name': 'domain_lookups_enabled', 'rest_name': 'domain-lookups-enabled'},
451 {'name': 'domain_name', 'rest_name': 'domain-name'},
452 {'name': 'default_gateway', 'rest_name': 'default-gateway'},
453 {'name': 'ntp_server', 'rest_name': 'ntp-server'},
454 {'name': 'time_zone', 'rest_name': 'time-zone'},
455 {'name': 'logging_enabled', 'rest_name': 'logging-enabled'},
456 {'name': 'logging_server', 'rest_name': 'logging-server'},
457 {'name': 'logging_level', 'rest_name': 'logging-level'},
458 )
459
Srikanth Vavilapalli22e58e92014-10-16 14:04:48 -0700460"""
srikanth116e6e82014-08-19 07:22:37 -0700461#
462# ------------------------------------------------------------
463
464class ControllerAlias(models.Model):
465
466 #
467 # fields ----------------------------------------
468
469 alias = models.CharField(
470 primary_key=True,
471 max_length=255,
472 help_text = "alias for controller",
473 verbose_name='alias',
474 validators=[SwitchAliasValidator()])
475
476 controller = models.ForeignKey(
477 Controller,
478 verbose_name='Controller')
479
480 #
481 # end fields ----------------------------------------
482
483 class Rest:
484 NAME = 'controller-alias'
srikanth116e6e82014-08-19 07:22:37 -0700485#
486# ------------------------------------------------------------
487
488class ControllerInterface(models.Model):
489
490 #
491 # fields ----------------------------------------
492
493 controller = models.ForeignKey(
494 Controller,
495 verbose_name="Controller ID")
496
497 type = models.CharField(
498 verbose_name='Interface Type',
499 help_text='Type of interface (e.g. "Ethernet")',
500 max_length=256,
501 default='Ethernet'
502 )
503
504 number = models.IntegerField(
505 verbose_name="Interface Number",
506 help_text='Number of interface (non-negative integer)',
507 default=0)
508
509 mode = models.CharField(
510 verbose_name='Mode',
511 help_text='Mode of configuring IP address ("dhcp" or "static")',
512 validators=[ EnumerationValidator(('dhcp', 'static'))],
513 max_length=32,
514 default='static')
515
516 ip = models.CharField(
517 verbose_name='IP Address',
518 help_text='IP Address for interface',
519 validators=[ IpValidator() ],
520 max_length=15,
521 default='',
522 blank=True)
523
524 netmask = models.CharField(
525 verbose_name='Netmask',
526 help_text='Netmask',
527 validators=[ IpValidator() ],
528 max_length=15,
529 default='',
530 blank=True)
531
532 # provide a link between the underlying interface layer
533 # and this model's 'index number' to help manage discovered_ip
534 mac = models.CharField(
535 verbose_name="MAC Address",
536 help_text="MAC Address",
537 max_length=17,
538 validators = [validate_mac_address],
539 blank=True,
540 null=True)
541
542 discovered_ip = models.CharField(
543 verbose_name='Discovered IP Address',
544 help_text='Discovered IP Address for interface',
545 validators=[ IpValidator() ],
546 max_length=15,
547 default='',
548 blank=True)
549
550
551# in_acl = models.ForeignKey(
552# ControllerAcl,
553# verbose_name = 'Controller input acl',
554# blank=True,
555# null=True)
556
557# out_acl = models.ForeignKey(
558# ControllerAcl,
559# verbose_name = 'Controller output acl',
560# blank=True,
561# null=True)
562
563 #
564 # end fields ----------------------------------------
565
566 class CassandraSettings:
567 COMPOUND_KEY_FIELDS = ('controller', 'type', 'number')
568
569 class Rest:
570 NAME = 'controller-interface'
571 FIELD_INFO = (
572 {'name': 'discovered_ip', 'rest_name': 'discovered-ip'},
573# {'name': 'in_acl', 'rest_name': 'in-acl'},
574# {'name': 'out_acl', 'rest_name': 'out-acl'},
575 )
576
577
578#
579# ------------------------------------------------------------
580
581class FirewallRule(models.Model):
582
583 #
584 # fields ----------------------------------------
585
586 interface = models.ForeignKey(
587 ControllerInterface,
588 verbose_name="Controller Interface")
589
590 action = models.CharField(
591 max_length=8,
592 validators=[ EnumerationValidator(('allow', 'deny', 'reject'))],
593 default='allow',
594 blank=True)
595
596 src_ip = models.CharField(
597 verbose_name='Source IP',
598 help_text='IP Address to allow traffic from',
599 validators=[ IpValidator() ],
600 max_length=15,
601 default='',
602 blank=True)
603
604 vrrp_ip = models.CharField(
605 verbose_name='Local IP',
606 help_text='(Local) IP Address to allow traffic to',
607 validators=[ IpValidator() ],
608 max_length=15,
609 default='',
610 blank=True)
611
612 port = models.IntegerField(
613 verbose_name='Port Number',
614 help_text='Port Number',
615 validators=[ RangeValidator(0,2**16-1) ],
616 default=0,
617 blank=True)
618
619 proto = models.CharField(
620 verbose_name="ip proto",
621 help_text="ip protocol (tcp, udp or vrrp)", #TODO validator
622 validators=[ UfwProtocolValditor() ],
623 max_length=4,
624 default='',
625 blank=True)
626
627 #
628 # end fields ----------------------------------------
629
630 class CassandraSettings:
631 COMPOUND_KEY_FIELDS = ('interface', 'src_ip', 'vrrp_ip', 'port', 'proto')
632
633 class Rest:
634 NAME = 'firewall-rule'
635 FIELD_INFO = (
636 {'name': 'src_ip', 'rest_name': 'src-ip'},
637 {'name': 'vrrp_ip', 'rest_name': 'vrrp-ip'},
638 )
639
640#
641# ------------------------------------------------------------
642
643class ControllerDomainNameServer(models.Model):
644
645 controller = models.ForeignKey(
646 Controller,
647 verbose_name="Controller ID",
648 default=None,
649 null=True)
650
651 ip = models.CharField(
652 verbose_name='IP Address',
653 help_text='IP Address of domain name server',
654 validators=[ IpValidator() ],
655 max_length=15,
656 default='')
657
658 timestamp = models.IntegerField(
659 verbose_name='timestamp',
660 help_text='Timestamp to determine order of domain name servers',
661 default = get_timestamp,
662 null=True,
663 blank=True,
664 )
665
666 #
667 # end fields ----------------------------------------
668
669 class CassandraSettings:
670 COMPOUND_KEY_FIELDS = ('controller', 'ip')
671
672 def validate_unique(self, exclude = None):
673 try:
674 exists = ControllerDomainNameServer.objects.get(controller = self.controller,
675 ip = self.ip)
676 if exists.timestamp != self.timestamp:
677 print 'SHAZAM', self.timestamp
678 self.timestamp = exists.timestamp
679 except:
680 pass
681
682 class Rest:
683 NAME = 'controller-domain-name-server'
684 FIELD_INFO = (
685 )
Srikanth Vavilapalli22e58e92014-10-16 14:04:48 -0700686"""
srikanth116e6e82014-08-19 07:22:37 -0700687#
688# ------------------------------------------------------------
689
690class Switch(models.Model):
691 switch_id_length = 23
692 #
693 # fields ----------------------------------------
694
695 dpid = models.CharField(
696 primary_key=True,
697 verbose_name='Switch DPID',
698 help_text='Switch DPID - 64-bit hex separated by :',
699 max_length=switch_id_length,
700 validators=[ validate_dpid ])
701
702 controller = models.ForeignKey(
703 Controller,
704 verbose_name='Controller ID',
705 blank=True,
706 null=True)
707
708 socket_address = models.CharField(
709 verbose_name='Socket Address',
710 help_text='Socket address used for connection to controller',
711 max_length=64,
712 blank=True,
713 null=True)
714
715 ip = models.CharField(
716 verbose_name='IP Address',
717 help_text='IP Address used for connection from controller',
718 validators=[ IpValidator() ],
719 max_length=15,
720 blank=True,
721 null=True)
722
723 active = models.BooleanField(
724 verbose_name='Active',
725 help_text='Switch is active (i.e. connected to a controller)',
726 default=False)
727
728 connected_since = models.DateTimeField(
729 verbose_name='Last Connect Time',
730 help_text='Time when the switch connected to the controller',
731 blank=True,
732 null=True)
733
734 dp_desc = models.CharField(
735 verbose_name='Description',
736 max_length=256,
737 blank=True,
738 null=True)
739
740 hw_desc = models.CharField(
741 verbose_name='Hardware Description',
742 max_length=256,
743 blank=True,
744 null=True)
745
746 sw_desc = models.CharField(
747 verbose_name='Software Description',
748 max_length=256,
749 blank=True,
750 null=True)
751
752 serial_num = models.CharField(
753 verbose_name='Serial Number',
754 max_length=32,
755 blank=True,
756 null=True)
757
758 capabilities = models.IntegerField(
759 verbose_name='Capabilities',
760 help_text='Openflow switch capabilities',
761 validators=[ RangeValidator(0,2**32-1) ],
762 default=0)
763
764 tunneling_supported = models.BooleanField(
765 default=False,
766 )
767
768 buffers = models.IntegerField(
769 verbose_name='Max Packets',
770 help_text='Maximum number of packets buffered by the switch',
771 validators=[ RangeValidator(0,2**32-1) ],
772 blank=True,
773 null=True)
774
775 tables = models.IntegerField(
776 verbose_name='Max Tables',
777 help_text='Number of tables supported by the switch',
778 validators=[ RangeValidator(0,2**8-1) ],
779 blank=True,
780 null=True)
781
782 actions = models.IntegerField(
783 verbose_name='Actions',
784 help_text='Actions supported by the switch',
785 validators=[ RangeValidator(0,2**32-1) ],
786 default=0)
787
788 #
789 # end fields ----------------------------------------
790
791 # LOOK! we should have an origin field to distinguish
792 # between user-specified switches and 'discovered' switches
793
794 def __unicode__(self):
795 return "%s" % self.dpid
796
797 class Rest:
798 NAME = 'switch'
799 FIELD_INFO = (
800 {'name': 'socket_address', 'rest_name': 'socket-address'},
801 {'name': 'ip', 'rest_name': 'ip-address'},
802 {'name': 'connected_since', 'rest_name': 'connected-since'},
803 {'name': 'dp_desc', 'rest_name': 'dp-desc'},
804 {'name': 'hw_desc', 'rest_name': 'hw-desc'},
805 {'name': 'sw_desc', 'rest_name': 'sw-desc'},
806 {'name': 'serial_num', 'rest_name': 'serial-num'},
807 {'name': 'tunneling_supported', 'rest_name': 'tunnel-supported'},
808 )
srikanth116e6e82014-08-19 07:22:37 -0700809#
810# ------------------------------------------------------------
811# SwitchConfig
812# Any 'configured' (non-discovered) state associated with
813# a switch.
814#
815# tunnel_termination; when enabled, tunnels are constructed
816# to any other tunnel_termination switch, building a mesh
817# of open-flow enabled switches. Typicall Used in virtualized
818# environments, where openflow switches are not intended to
819# exist in the path.
820#
821
822class SwitchConfig(models.Model):
823 switch_id_length = 23
824 #
825 # fields ----------------------------------------
826
827 dpid = models.CharField(
828 primary_key=True,
829 verbose_name='Switch DPID',
830 help_text='Switch DPID - 64-bit hex separated by :',
831 max_length=switch_id_length,
832 validators=[ validate_dpid ])
833
834 core_switch = models.BooleanField(
835 default=False,
836 help_text='Identify core switches'
837 )
838
839 tunnel_termination = models.CharField(
840 verbose_name='Tunnel Termination',
841 help_text='Tunnel Termination ("enabled" "disabled" "default")',
842 validators=[ EnumerationValidator(('enabled', 'disabled', 'default'))],
843 default = 'default',
844 max_length=16)
845
846 #
847 # end fields ----------------------------------------
848
849
850 def validate_unique(self, exclude = None):
851 self.dpid = self.dpid.lower()
852
853 class Rest:
854 NAME = 'switch-config'
855 FIELD_INFO = (
856 {'name': 'tunnel_termination', 'rest_name': 'tunnel-termination'},
857 {'name': 'core_switch', 'rest_name': 'core-switch'},
858 )
859
srikanth116e6e82014-08-19 07:22:37 -0700860#
861# ------------------------------------------------------------
862
863class SwitchAlias(models.Model):
864
865 #
866 # fields ----------------------------------------
867
868 id = models.CharField(
869 primary_key=True,
870 max_length=255,
871 help_text = "alias for switch",
872 verbose_name='alias',
873 validators=[SwitchAliasValidator()])
874
875 switch = models.ForeignKey(
876 SwitchConfig,
877 verbose_name='Switch DPID')
878
879 #
880 # end fields ----------------------------------------
881
882 class Rest:
883 NAME = 'switch-alias'
884
Srikanth Vavilapalli22e58e92014-10-16 14:04:48 -0700885"""
srikanth116e6e82014-08-19 07:22:37 -0700886#
887# ------------------------------------------------------------
888
889class Port(models.Model):
890 #
891 # fields ----------------------------------------
892 #
893 # This table isn't intended to be updated via the rest api,
894 # sdnplatform writes the table to describe a switch.
895 #
896 # The 'number' in the port model is the openflow port number,
897 # which is a value used in setting up flow entries. This is
898 # not an interface name; the 'interface name' is the 'name'
899 # field below. This table provides a mapping from the switch
900 # dpid and port number to an 'interface name'.
901 #
902 # Since interface names can be configured on demand by the
903 # switch, for example to name a tunnel, its not easy to
904 # "guess" interface names without the switch reporting
905 # what interface names exist. This leads to difficulty
906 # in preconfiguring any associations with <switch, interface name>
907 #
908
909 # Unique identifier for the port
910 # combination of the switch DPID and the port number
911 id = models.CharField(
912 primary_key=True,
913 verbose_name='Port ID',
914 help_text = '#|switch|number',
915 max_length=48)
916
917 switch = models.ForeignKey(
918 Switch,
919 verbose_name='Switch DPID')
920
921 number = models.IntegerField(
922 verbose_name='OF #',
923 help_text="Port open flow number",
924 validators=[ RangeValidator(0,2**16-1) ])
925
926 hardware_address = models.CharField(
927 verbose_name="MAC Address",
928 help_text="Port MAC Address",
929 max_length=17,
930 validators = [validate_mac_address],
931 blank=True,
932 null=True)
933
934 name = models.CharField(
935 verbose_name='Name',
936 help_text="Port name",
937 max_length=32,
938 blank=True,
939 null=True)
940
941 config = models.IntegerField(
942 verbose_name='Configuration',
943 help_text='Configuration Flags',
944 validators=[ RangeValidator(0,2**32-1) ],
945 default=0)
946
947 state = models.IntegerField(
948 verbose_name="State",
949 help_text="State Flags",
950 validators=[ RangeValidator(0,2**32-1) ],
951 default=0)
952
953 current_features = models.IntegerField(
954 verbose_name='Current',
955 help_text='Current Features',
956 validators=[ RangeValidator(0,2**32-1) ],
957 default=0)
958
959 advertised_features = models.IntegerField(
960 verbose_name='Advertised',
961 help_text='Advertised Features',
962 validators=[ RangeValidator(0,2**32-1) ],
963 default=0)
964
965 supported_features = models.IntegerField(
966 verbose_name='Supported',
967 help_text='Supported Features',
968 validators=[ RangeValidator(0,2**32-1) ],
969 default=0)
970
971 peer_features = models.IntegerField(
972 verbose_name='Peer',
973 help_text='Peer Features',
974 validators=[ RangeValidator(0,2**32-1) ],
975 default=0)
976
977 #
978 # end fields ----------------------------------------
979
980 def __unicode__(self):
981 return "%s" % (self.id,)
982
983 class Rest:
984 NAME = 'port'
985 FIELD_INFO = (
986 {'name': 'hardware_address', 'rest_name': 'hardware-address'},
987 {'name': 'current_features', 'rest_name': 'current-features'},
988 {'name': 'advertised_features', 'rest_name': 'advertised-features'},
989 {'name': 'supported_features', 'rest_name': 'supported-features'},
990 {'name': 'peer_features', 'rest_name': 'peer-features'},
991 )
992
993#
994# ------------------------------------------------------------
995
996class PortAlias(models.Model):
997
998 #
999 # fields ----------------------------------------
1000
1001 id = models.CharField(
1002 primary_key=True,
1003 max_length=255,
1004 help_text = "alias for port",
1005 verbose_name='alias',
1006 validators=[PortAliasValidator()])
1007
1008 port = models.ForeignKey(
1009 Port,
1010 help_text = "foreign key for port alias",
1011 verbose_name='Port ID')
1012
1013 #
1014 # end fields ----------------------------------------
1015
1016 class Rest:
1017 NAME = 'port-alias'
1018#
1019# ------------------------------------------------------------
1020
1021class SwitchInterfaceConfig(models.Model):
1022 if_name_len = 32
1023 #
1024 # fields ----------------------------------------
1025
1026 switch = models.ForeignKey(
1027 SwitchConfig,
1028 verbose_name='Switch')
1029
1030 if_name = models.CharField(
1031 verbose_name='If Name',
1032 validators=[ SafeForPrimaryKeyValidator() ],
1033 max_length=32)
1034
1035 mode = models.CharField(
1036 verbose_name='Mode',
1037 help_text='Interface Mode ("external", "default")',
1038 validators=[ EnumerationValidator(('external','default'))],
1039 max_length=32,
1040 default='default')
1041
1042 broadcast = models.BooleanField(
1043 default=False,
1044 verbose_name='Broadcast',
1045 help_text='True when interfaces is an uplink to a legacy net',
1046 )
1047
1048 #
1049 # end fields ----------------------------------------
1050
1051 def __unicode__(self):
1052 return "%s" % (self.id)
1053
1054 class CassandraSettings:
1055 COMPOUND_KEY_FIELDS = ('switch', 'if_name')
1056
1057 def validate_unique(self, exclude = None):
1058 self.broadcast = False
1059 if self.mode == 'external':
1060 self.broadcast = True
1061
1062 class Rest:
1063 NAME = 'switch-interface-config'
1064 FIELD_INFO = (
1065 # By using 'name' here, the 'name' from the port is identified
1066 # in the complete-from-another procedure
1067 {'name': 'if_name', 'rest_name': 'name'},
1068 )
1069
1070
1071#
1072# ------------------------------------------------------------
1073
1074class SwitchInterfaceAlias(models.Model):
1075 switch_interface_alias_length = 255
1076 #
1077 # fields ----------------------------------------
1078
1079 id = models.CharField(
1080 primary_key = True,
1081 verbose_name = 'Switch Interface Alias',
1082 help_text = 'alias',
1083 max_length = switch_interface_alias_length,
1084 validators=[HostAliasValidator()])
1085
1086 switch_interface = models.ForeignKey(
1087 SwitchInterfaceConfig,
1088 verbose_name='Switch Interface',
1089 )
1090
1091 #
1092 # end fields ----------------------------------------
1093
1094 class Rest:
1095 NAME = 'switch-interface-alias'
1096 FIELD_INFO = (
1097 {'name': 'switch_interface', 'rest_name': 'switch-interface'},
1098 )
1099#
1100# ------------------------------------------------------------
1101
1102class StaticFlowTableEntry(models.Model):
1103 #
1104 # fields ----------------------------------------
1105
1106 name = models.CharField(
1107 primary_key=True,
1108 verbose_name='Name',
1109 max_length=80)
1110
1111 switch = models.ForeignKey(
1112 SwitchConfig,
1113 verbose_name="Switch DPID")
1114
1115 active = models.BooleanField(
1116 default=False)
1117
1118 # LOOK! we should hide the timeout values for static flow entry
1119 # definition as they are overwritten (unless we allow these to
1120 # overwrite the default that static flow pusher uses)
1121 idle_timeout = models.IntegerField(
1122 verbose_name="Idle Timeout",
1123 help_text="Expire flow after this many seconds of inactivity - default: 60",
1124 default=60,
1125 validators=[ RangeValidator(0, 2**16-1) ])
1126
1127 hard_timeout = models.IntegerField(
1128 verbose_name="Hard Timeout",
1129 help_text="Seconds to expire flow, regardless of activity - default: 0",
1130 default=0,
1131 validators=[ RangeValidator(0, 2**16-1) ])
1132
1133 priority = models.IntegerField(
1134 verbose_name="Priority",
1135 help_text="Priority of the flow entry",
1136 default=32768,
1137 validators=[ RangeValidator(0, 2**16-1) ])
1138
1139 cookie = models.IntegerField(
1140 verbose_name="Cookie",
1141 default=0) # 64-bit
1142
1143 #
1144 # match fields
1145 #
1146
1147 # LOOK! Need a file of python openflow constants
1148
1149 # LOOK! we should hide this also or at least
1150 # for static flow entries say it is ignored
1151 wildcards = models.IntegerField(
1152 verbose_name="Wildcards",
1153 default=0,
1154 validators=[ RangeValidator(0,2**32-1) ])
1155
1156 in_port = models.IntegerField(
1157 verbose_name="Ingress Port",
1158 blank=True,
1159 help_text="Open flow port number of ingress port",
1160 null=True,
1161 validators = [ RangeValidator(0, 2**16-1) ] )
1162
1163 dl_src = models.CharField(
1164 verbose_name="Src MAC",
1165 help_text="This is a 48-bit quantity specified in xx:xx:xx:xx:xx:xx format",
1166 max_length=17,
1167 blank=True,
1168 null=True,
1169 validators = [ validate_mac_address ] )
1170
1171 dl_dst = models.CharField(
1172 verbose_name="Dst MAC",
1173 help_text="Destination MAC address in the frames",
1174 max_length=17,
1175 blank=True,
1176 null=True,
1177 validators = [ validate_mac_address ] )
1178
1179 dl_vlan = models.IntegerField(
1180 verbose_name="VLAN ID",
1181 help_text="VLAN ID in the frames",
1182 blank=True,
1183 null=True,
1184 validators = [ RangeValidator(0, 2**12-1) ])
1185
1186 dl_vlan_pcp = models.IntegerField(
1187 verbose_name="VLAN Priority",
1188 help_text="VLAN ID in the frames",
1189 blank=True,
1190 null=True,
1191 validators = [ RangeValidator(0, 2**3-1) ])
1192
1193 dl_type = models.IntegerField(
1194 verbose_name="Ether Type",
1195 help_text="Ether(L3) type",
1196 blank=True,
1197 null=True,
1198 validators = [ RangeValidator(0, 2**16-1) ])
1199
1200 nw_tos = models.IntegerField(
1201 verbose_name="TOS Bits",
1202 help_text="TOS bits in the frame",
1203 blank=True,
1204 null=True,
1205 validators = [ RangeValidator(0, 2**6-1) ]) # 6-bit DSCP value
1206
1207 nw_proto = models.IntegerField(
1208 verbose_name="Protocol",
1209 help_text="IP (L4) protocol in the packets",
1210 blank=True,
1211 null=True,
1212 validators = [ RangeValidator(0, 2**8-1) ])
1213
1214 nw_src = models.CharField(
1215 verbose_name="Src IP",
1216 help_text="IP v4 source address in dotted decimal a.b.c.d w/ optional mask (ex: /24)",
1217 max_length=18,
1218 validators = [ CidrValidator(mask_required=False) ],
1219 blank=True,
1220 null=True)
1221
1222 nw_dst = models.CharField(
1223 verbose_name="Dst IP",
1224 help_text="IP v4 destination address in dotted decimal a.b.c.d w/ optional mask (ex: /24)",
1225 validators=[ CidrValidator(mask_required=False) ],
1226 max_length=18,
1227 blank=True,
1228 null=True )
1229
1230 tp_src = models.IntegerField(
1231 verbose_name="Src Port",
1232 help_text="Source (TCP/UDP) port",
1233 blank=True,
1234 null=True,
1235 validators=[ RangeValidator(0, 2**16-1) ])
1236
1237 tp_dst = models.IntegerField(
1238 verbose_name="Dst Port",
1239 help_text="Destination (TCP/UDP) port",
1240 blank=True,
1241 null=True,
1242 validators=[ RangeValidator(0, 2**16-1) ])
1243
1244 # LOOK! have to figure out how to expose actions in the CLI - this is ugly/brittle
1245 actions = models.CharField(
1246 verbose_name = "Actions",
1247 help_text="This is a comma-separated list of actions - a la dpctl",
1248 max_length=1024,
1249 blank=True,
1250 null=True)
1251
1252 #
1253 # end fields ----------------------------------------
1254
1255 def __unicode__(self):
1256 return self.name
1257
1258
1259 class Rest:
1260 NAME = 'flow-entry'
1261 FIELD_INFO = (
1262 {'name': 'idle_timeout', 'rest_name': 'idle-timeout'},
1263 {'name': 'hard_timeout', 'rest_name': 'hard-timeout'},
1264 {'name': 'in_port', 'rest_name': 'ingress-port'},
1265 {'name': 'dl_src', 'rest_name': 'src-mac'},
1266 {'name': 'dl_dst', 'rest_name': 'dst-mac'},
1267 {'name': 'dl_vlan', 'rest_name': 'vlan-id'},
1268 {'name': 'dl_vlan_pcp', 'rest_name': 'vlan-priority'},
1269 {'name': 'dl_type', 'rest_name': 'ether-type'},
1270 {'name': 'nw_tos', 'rest_name': 'tos-bits'},
1271 {'name': 'nw_proto', 'rest_name': 'protocol'},
1272 {'name': 'nw_src', 'rest_name': 'src-ip'},
1273 {'name': 'nw_dst', 'rest_name': 'dst-ip'},
1274 {'name': 'tp_src', 'rest_name': 'src-port'},
1275 {'name': 'tp_dst', 'rest_name': 'dst-port'},
1276 {'name': 'actions', 'rest_name': 'actions'},
1277 )
Fahad Naeem Khan0c1c7b32014-10-07 16:22:23 -07001278
srikanth116e6e82014-08-19 07:22:37 -07001279#
1280# ------------------------------------------------------------
1281
1282class Link(models.Model):
1283 #
1284 # fields ----------------------------------------
1285
1286 id = models.CharField(
1287 primary_key=True,
1288 verbose_name='Link ID',
1289 max_length=64)
1290
1291 src_switch = models.ForeignKey(
1292 Switch,
1293 verbose_name='Src Switch DPID',
1294 related_name='src_link_set')
1295 #src_switch_id = models.CharField(
1296 # verbose_name='Src Switch ID',
1297 # max_length=32)
1298
1299 name = models.CharField(
1300 verbose_name='Name',
1301 help_text="Link name",
1302 max_length=32,
1303 blank=True,
1304 null=True)
1305
1306 src_port = models.IntegerField(
1307 verbose_name="Src Port",
1308 validators=[ RangeValidator(0, 2**16-1) ])
1309
1310 src_port_state = models.IntegerField(
1311 verbose_name="Src Port State",
1312 help_text="Source Port State Flags",
1313 validators=[ RangeValidator(0,2**32-1) ],
1314 default=0)
1315
1316 dst_switch = models.ForeignKey(
1317 Switch,
1318 verbose_name='Dst Switch DPID',
1319 related_name='dst_link_set')
1320 #dst_switch_id = models.CharField(
1321 # verbose_name='Dst Switch ID',
1322 # max_length=32)
1323
1324 dst_port = models.IntegerField(
1325 verbose_name="Dst Port",
1326 help_text="Destination Port",
1327 validators=[ RangeValidator(0, 2**16-1) ])
1328
1329 dst_port_state = models.IntegerField(
1330 verbose_name="Dst Port State",
1331 help_text="Destination Port State Flags",
1332 validators=[ RangeValidator(0,2**32-1) ],
1333 default=0)
1334
1335 link_type = models.CharField(
1336 verbose_name='Link Type',
1337 help_text="Link type",
1338 max_length=10,
1339 blank=True,
1340 null=True)
1341 #
1342 # end fields ----------------------------------------
1343
1344 def __unicode__(self):
1345 return "%s" % self.id
1346
1347 class Rest:
1348 NAME = 'link'
1349 FIELD_INFO = (
1350 {'name': 'src_switch', 'rest_name': 'src-switch'},
1351 {'name': 'src_port', 'rest_name': 'src-port'},
1352 {'name': 'src_port_state', 'rest_name': 'src-port-state'},
1353 {'name': 'dst_switch', 'rest_name': 'dst-switch'},
1354 {'name': 'dst_port', 'rest_name': 'dst-port'},
1355 {'name': 'dst_port_state', 'rest_name': 'dst-port-state'},
1356 {'name': 'link_type', 'rest_name': 'link-type'}
1357 )
1358
srikanthf2c888b2014-08-20 10:46:55 -07001359"""
Srikanth Vavilapalli669ba8a2014-10-16 11:41:19 -07001360"""
srikanth116e6e82014-08-19 07:22:37 -07001361#
1362# ------------------------------------------------------------
1363# An address-space separation
1364
1365class AddressSpace (models.Model):
1366
1367 id_max_length = 64
1368
1369 #
1370 # fields ----------------------------------------
1371
1372 #
1373 # Unique name of the address-space
1374 #
1375 name = models.CharField(
1376 primary_key = True,
1377 verbose_name = 'Address Space Name',
1378 help_text = 'A unique name for an Address Space Seperation',
1379 validators = [ AddressSpaceNameValidator() ],
1380 max_length = id_max_length)
1381
1382 #
1383 # Verbose description of this rule.
1384 #
1385 description = models.CharField(
1386 verbose_name = 'Description',
1387 help_text = "Description of the address-space",
1388 max_length = 128,
1389 blank = True,
1390 null = True)
1391
1392 #
1393 # Whether the configuration is active ? By default, it is active
1394 # Used to disable the configuration without having to delete the entire
1395 # address-space configuration construct.
1396 #
1397 active = models.BooleanField(
1398 verbose_name = 'Active',
1399 help_text = 'Is this Address Space active (default is True)',
1400 default = True)
1401
1402 #
1403 # Priority of this address-space during device matching when
1404 # compared to other address-spaces. Those at the same priority
1405 # are used in a determinisitc alphanetical order.
1406 #
1407 priority = models.IntegerField(
1408 verbose_name = 'Priority',
1409 help_text = 'Priority for this Address Space ' +
1410 '(higher numbers are higher priority)',
1411 default = 1000,
1412 validators = [ RangeValidator(0, 65535) ])
1413
1414 #
1415 # Seperator tag of this address-space in the data plane, such as vlan id.
1416 #
1417 vlan_tag_on_egress = models.IntegerField(
1418 verbose_name = 'Egress VLAN tag',
1419 help_text = 'Vlan Tag value used for this Address Space separation',
1420 default = None,
1421 blank = True,
1422 null = True,
1423 validators = [ RangeValidator(0, 4095) ])
1424
1425 #
1426 # Origin of this configured item
1427 #
1428 origin = models.CharField(
1429 verbose_name = "Origin",
1430 help_text = "Values: cli, rest, other packages",
1431 max_length = 64, # in future we might use SW GUIDs for this field
1432 blank = True,
1433 null = True)
1434
1435 #
1436 # end fields ----------------------------------------
1437
1438 def __unicode__ (self):
1439 return self.name
1440
1441 class Rest:
1442 NAME = 'address-space'
1443 FIELD_INFO = (
1444 {'name': 'vlan_tag_on_egress', 'rest_name':'vlan-tag-on-egress'},
1445 )
1446
1447#
1448# ------------------------------------------------------------
1449# An identifier rule in address-space separation
1450
1451class AddressSpaceIdentifierRule (models.Model):
1452 rule_max_length = 32
1453
1454 #
1455 # fields ----------------------------------------
1456
1457 #
1458 # Create a reference to the enclosing address-space construct.
1459 #
1460 address_space = models.ForeignKey(
1461 AddressSpace,
1462 verbose_name = 'Address Space Identifier')
1463
1464 #
1465 # Unique rule identifier name under this address-space.
1466 #
1467 rule = models.CharField(
1468 verbose_name = 'Address Space Rule Identifier',
1469 max_length = rule_max_length)
1470
1471 #
1472 # Verbose description of this rule.
1473 #
1474 description = models.CharField(
1475 verbose_name = 'Description',
1476 help_text = "Description of rule",
1477 max_length = 128,
1478 blank = True,
1479 null = True)
1480
1481 #
1482 # Whether the configuration is active ? By default, it is active
1483 # Used to disable the configuration without having to delete the entire
1484 # address-space identifier-rule configuration construct.
1485 #
1486 active = models.BooleanField(
1487 verbose_name = 'Active',
1488 help_text = 'If this interface is active (default is True)',
1489 default = True)
1490
1491 #
1492 # Priority of this address-space during device matching when
1493 # compared to other address-spaces. Those at the same priority
1494 # are used in a determinisitc alphanetical order.
1495 #
1496 priority = models.IntegerField(
1497 verbose_name = 'Priority',
1498 help_text = 'Priority for this interface rule ' +
1499 '(higher numbers are higher priority)',
1500 default = 32768,
1501 validators = [ RangeValidator(0, 65535) ])
1502
1503 #
1504 # DPID of the Switch which sent the packet
1505 #
1506 switch = models.CharField(
1507 verbose_name = 'Switch DPID',
1508 max_length = Switch.switch_id_length,
1509 help_text = 'Switch DPID or switch alias',
1510 validators = [ validate_dpid ],
1511 null = True,
1512 blank = True)
1513
1514 #
1515 # Range of ports in which the packet came from
1516 #
1517 ports = models.CharField(
1518 verbose_name = "Port Range Spec",
1519 help_text = 'Port range (e.g. C12 or B1,A22-25)',
1520 max_length = 256,
1521 validators = [ PortRangeSpecValidator() ],
1522 blank = True,
1523 null = True)
1524
1525 #
1526 # Range of VLAN tags
1527 #
1528 vlans = models.CharField(
1529 verbose_name = "VLAN Range Spec",
1530 help_text = "VLAN(s) (e.g. 5 or 5-10,4010-4050)",
1531 max_length = 256,
1532 validators = [ VLANRangeSpecValidator() ],
1533 blank = True,
1534 null = True)
1535
1536 #
1537 # NameValue pair of tags
1538 #
1539 tag = models.CharField(
1540 verbose_name = "Tag Spec",
1541 help_text = "Tag values (e.g. namespace.tagname=value)",
1542 max_length = 256,
1543 validators = [ TagSpecValidator() ],
1544 blank = True,
1545 null = True)
1546
1547 #
1548 # end fields ----------------------------------------
1549
1550 def __unicode__ (self):
1551 return self.id
1552
1553 class CassandraSettings:
1554 COMPOUND_KEY_FIELDS = ('address_space', 'rule')
1555
1556 class Rest:
1557 NAME = 'address-space-identifier-rule'
1558 FIELD_INFO = (
1559 {'name': 'description', 'rest_name': 'description'},
1560 {'name': 'address_space', 'rest_name': 'address-space'},
1561 {'name': 'active', 'rest_name': 'active'},
1562 {'name': 'priority', 'rest_name': 'priority'},
1563 {'name': 'switch', 'rest_name': 'switch'},
1564 {'name': 'ports', 'rest_name': 'ports'},
1565 {'name': 'vlans', 'rest_name': 'vlans'},
1566 {'name': 'tag', 'rest_name': 'tag'},
1567 )
srikanth116e6e82014-08-19 07:22:37 -07001568#
1569# ------------------------------------------------------------
Srikanth Vavilapalli22e58e92014-10-16 14:04:48 -07001570"""
srikanth116e6e82014-08-19 07:22:37 -07001571class HostConfig(models.Model):
1572 host_id_length = 17
1573 #
1574 # fields ----------------------------------------
1575
srikanthf2c888b2014-08-20 10:46:55 -07001576 #address_space = models.ForeignKey(
1577 # AddressSpace,
1578 # verbose_name = "Address space name")
srikanth116e6e82014-08-19 07:22:37 -07001579
1580 mac = models.CharField(
1581 verbose_name="MAC Address",
1582 max_length=host_id_length,
1583 validators = [validate_mac_address])
1584
1585 vlan = models.CharField(
1586 verbose_name='VLAN',
1587 help_text='VLAN Associated with host',
1588 max_length=4,
1589 validators=[RangeValidator(1, 4095)],
1590 blank=True,
1591 default='')
1592
1593 #
1594 # end fields ----------------------------------------
1595
1596 def __unicode__(self):
1597 self.mac = self.mac.lower()
srikanthf2c888b2014-08-20 10:46:55 -07001598 #return "%s::%s" % (self.addressSpace, self.mac)
1599 return "%s" % (self.addressSpace)
srikanth116e6e82014-08-19 07:22:37 -07001600
1601 class CassandraSettings:
srikanthf2c888b2014-08-20 10:46:55 -07001602 #COMPOUND_KEY_FIELDS = ('address_space', 'vlan', 'mac')
1603 COMPOUND_KEY_FIELDS = ('vlan', 'mac')
srikanth116e6e82014-08-19 07:22:37 -07001604
1605 def validate_unique(self, exclude = None):
1606 # Invoke the default validator; error out if the vns already exists
1607 super(HostConfig, self).validate_unique(exclude)
srikanthf2c888b2014-08-20 10:46:55 -07001608 #if self.vlan and str(self.address_space) != 'default':
1609 # raise ValidationError('host: vlan configured for '
1610 # 'address-space other than "default" %s' % self.address_space)
srikanth116e6e82014-08-19 07:22:37 -07001611
1612 class Rest:
1613 NAME = 'host-config'
1614 FIELD_INFO = (
srikanthf2c888b2014-08-20 10:46:55 -07001615 #{'name': 'address_space', 'rest_name': 'address-space'},
srikanth116e6e82014-08-19 07:22:37 -07001616 )
Srikanth Vavilapalli22e58e92014-10-16 14:04:48 -07001617"""
srikanth116e6e82014-08-19 07:22:37 -07001618#
1619# ------------------------------------------------------------
1620
1621class HostSecurityIpAddress(models.Model):
1622 host = models.ForeignKey(
1623 HostConfig,
1624 verbose_name='Host ID')
1625
1626 ip = models.CharField(
1627 verbose_name='IP Address',
1628 help_text='IP Address used to associate with host',
1629 validators=[ IpValidator() ],
1630 max_length=15,
1631 blank=True,
1632 null=True)
1633
1634 #
1635 # end fields ----------------------------------------
1636
1637 def __unicode__(self):
1638 return self.id
1639
1640 class CassandraSettings:
1641 COMPOUND_KEY_FIELDS = ('host', 'ip')
1642
1643 class Rest:
1644 NAME = 'host-security-ip-address'
1645 FIELD_INFO = (
1646 {'name': 'ip', 'rest_name': 'ip-address'},
1647 )
1648
1649
1650#
1651# ------------------------------------------------------------
1652
1653class HostSecurityAttachmentPoint(models.Model):
1654 host = models.ForeignKey(
1655 HostConfig,
1656 verbose_name='Host ID')
1657
1658 dpid = models.CharField(
1659 verbose_name = 'Switch DPID',
1660 max_length = Switch.switch_id_length,
1661 help_text = 'Switch DPID or switch alias',
1662 validators = [ validate_dpid ],
1663 null = True,
1664 blank = True)
1665
1666 if_name_regex = models.CharField(
1667 verbose_name='If Name Regex',
1668 help_text='Interface name regular expression',
1669 max_length=64,
1670 validators = [SafeForPrimaryKeyValidator(), IsRegexValidator()],
1671 blank = True,
1672 null = False,
1673 )
1674
1675
1676 #
1677 # end fields ----------------------------------------
1678
1679 def __unicode__(self):
1680 return self.id
1681
1682 class CassandraSettings:
1683 COMPOUND_KEY_FIELDS = ('host', 'dpid', 'if_name_regex')
1684
1685 class Rest:
1686 NAME = 'host-security-attachment-point'
1687 FIELD_INFO = (
1688 {'name': 'if_name_regex', 'rest_name': 'if-name-regex'},
1689 )
1690
1691#
1692# ------------------------------------------------------------
1693
1694class HostAlias(models.Model):
1695 host_alias_length = 255
1696 #
1697 # fields ----------------------------------------
1698
1699 id = models.CharField(
1700 primary_key = True,
1701 verbose_name = 'Host Alias',
1702 help_text = 'alias',
1703 max_length = host_alias_length,
1704 validators=[HostAliasValidator()])
1705
1706 host = models.ForeignKey(
1707 HostConfig,
1708 verbose_name='Host ID')
1709
1710 #
1711 # end fields ----------------------------------------
1712
1713 class Rest:
1714 NAME = 'host-alias'
1715
srikanth116e6e82014-08-19 07:22:37 -07001716class VlanConfig(models.Model):
1717 #
1718 # fields ----------------------------------------
1719 vlan = models.IntegerField(
1720 primary_key = True,
1721 verbose_name='VLAN',
1722 help_text='VLAN Number',
1723 validators=[RangeValidator(0, 4095)],
1724 )
1725
1726 #
1727 # end fields ----------------------------------------
1728
1729 def __unicode__(self):
1730 if self.vlan:
1731 return "%s vlan %s" % (self.vlan)
1732 else:
1733 return "%s vlan %s" % (self.vlan)
1734
1735 class Rest:
1736 NAME = 'vlan-config'
1737
1738#
1739# ------------------------------------------------------------
1740# A Static ARP table separation
1741
1742class StaticArp (models.Model):
1743
1744 id_max_length = 64
1745 #
1746 # fields ----------------------------------------
1747 ip = models.CharField(
1748 primary_key=True,
1749 verbose_name='IP Address',
1750 validators=[ IpValidator() ],
1751 max_length=15)
1752 mac = models.CharField(
1753 verbose_name="MAC Address",
1754 max_length=17,
1755 validators = [validate_mac_address])
1756 #
1757 # Origin of this configured item
1758 #
1759 origin = models.CharField(
1760 verbose_name = "Origin",
1761 help_text = "Values: cli, rest, other packages",
1762 max_length = 64, # in future we might use SW GUIDs for this field
1763 blank = True,
1764 null = True)
1765
1766 #
1767 # end fields ----------------------------------------
1768
1769 def __unicode__ (self):
1770 return self.id
1771
1772 class Rest:
1773 NAME = 'static-arp'
1774
1775
1776
1777#
1778# ------------------------------------------------------------
1779# A Tenant separation
1780
1781class Tenant (models.Model):
1782
1783 id_max_length = 64
1784 #
1785 # fields ----------------------------------------
1786
1787 #
1788 # Unique name of the tenant
1789 #
1790 name = models.CharField(
1791 primary_key = True,
1792 verbose_name = 'Tenant Name',
1793 help_text = 'A unique name for an Tenant',
1794 validators = [ TenantNameValidator() ],
1795 max_length = id_max_length)
1796
1797 #
1798 # Verbose description of this tenant.
1799 #
1800 description = models.CharField(
1801 verbose_name = 'Description',
1802 help_text = "Description of the tenant",
1803 max_length = 128,
1804 blank = True,
1805 null = True)
1806
1807 #
1808 # Whether the configuration is active ? By default, it is active
1809 # Used to disable the configuration without having to delete the entire
1810 # tenant configuration construct.
1811 #
1812 active = models.BooleanField(
1813 verbose_name = 'Active',
1814 help_text = 'Is this Tenant active (default is True)',
1815 default = True)
1816
1817 #
1818 # Origin of this configured item
1819 #
1820 origin = models.CharField(
1821 verbose_name = "Origin",
1822 help_text = "Values: cli, rest, other packages",
1823 max_length = 64, # in future we might use SW GUIDs for this field
1824 blank = True,
1825 null = True)
1826
1827 #
1828 # end fields ----------------------------------------
1829
1830 def __unicode__ (self):
1831 return self.name
1832
1833 def delete(self):
1834 if self.name=='default' or self.name =='system' or self.name =='external':
1835 raise ValidationError("Default/External/System Tenant can't be deleted")
1836 super(Tenant, self).delete()
1837 class Rest:
1838 NAME = 'tenant'
1839
1840
1841#
1842# ------------------------------------------------------------
1843# A virtual router separation
1844
1845class VirtualRouter (models.Model):
1846
1847 id_max_length = 64
1848 #
1849 # fields ----------------------------------------
1850 vrname = models.CharField(
1851 verbose_name = 'Virtual Router Name',
1852 help_text = 'A unique name for a virtual router',
1853 validators = [ GeneralNameValidator() ],
1854 max_length = id_max_length
1855 )
1856
1857 tenant = models.ForeignKey(
1858 Tenant,
1859 verbose_name='Tenant Name',
1860 )
1861 description = models.CharField(
1862 verbose_name = 'Description',
1863 help_text = "Description of the virtual router",
1864 max_length = 128,
1865 blank = True,
1866 null = True,
1867 )
1868
1869 #
1870 # Origin of this configured item
1871 #
1872 origin = models.CharField(
1873 verbose_name = "Origin",
1874 help_text = "Values: cli, rest, other packages",
1875 max_length = 64, # in future we might use SW GUIDs for this field
1876 blank = True,
1877 null = True)
1878
1879 #
1880 # end fields ----------------------------------------
1881
1882 def __unicode__ (self):
1883 return self.id
1884
1885 def validate_unique(self, exclude = None):
1886 # in fat tire, only one router per tenant can be defined. this can be removed later.
1887 error=False
1888 try:
1889 exists = VirtualRouter.objects.get(tenant = self.tenant)
1890 if exists.vrname !=self.vrname:
1891 error=True
1892 except:
1893 pass
1894 if error:
1895 raise ValidationError(" Virtual router %s has been defined for tenant %s, only one virtual router per tenant supported" % (exists.vrname,self.tenant))
1896
1897 class CassandraSettings:
1898 COMPOUND_KEY_FIELDS = ('tenant', 'vrname')
1899
1900 class Rest:
1901 NAME = 'virtualrouter'
1902
1903#
1904# ------------------------------------------------------------
1905# A virtual network segment
1906
1907class VNS(models.Model):
1908 id_max_length = 64
1909 #
1910 # fields ----------------------------------------
1911 vnsname = models.CharField(
1912 verbose_name='VNS ID',
1913 help_text='A unique name for a Virtual Network Segment',
1914 validators=[GeneralNameValidator()],
1915 max_length=id_max_length)
1916 tenant=models.ForeignKey(
1917 Tenant,
1918 verbose_name='Tenant ID',
1919 default='default')
1920 #
1921 # Verbose description of this rule.
1922 #
1923 description = models.CharField(
1924 verbose_name = 'Description',
1925 help_text = "Description of the VNS",
1926 max_length = 128,
1927 blank = True,
1928 null = True)
1929
1930 #
1931 # Reference to the address-space item. By default, we
1932 # implicitly use 'default' if this is not explicitly provided.
1933 #
1934 vns_address_space = models.ForeignKey(
1935 AddressSpace,
1936 verbose_name='Address Space Association',
1937 blank=True,
1938 null=True)
1939
1940 active = models.BooleanField(
1941 verbose_name='Active',
1942 help_text='If this VNS is active (default is True)',
1943 default=True)
1944
1945 priority = models.IntegerField(
1946 verbose_name='Priority',
1947 help_text='Priority for this VNS (higher numbers are higher priority)',
1948 default = 1000,
1949 validators=[RangeValidator(0, 65535)])
1950
1951 origin = models.CharField(
1952 verbose_name = "The origin/creator interface for this VNS",
1953 help_text="Values: cli, rest, other packages",
1954 max_length=64, # in future we might use SW GUIDs for this field
1955 blank=True,
1956 null=True)
1957
1958 arp_mode = models.CharField(
1959 verbose_name = "ARP Manager Config Mode",
1960 help_text="Values: always-flood, flood-if-unknown, drop-if-unknown",
1961 max_length=32,
1962 validators=[VnsArpModeValidator()],
1963 default='flood-if-unknown')
1964
1965 dhcp_mode = models.CharField(
1966 verbose_name = "DHCP Manager Config Mode",
1967 help_text = "Values: always-flood, flood-if-unknown, static",
1968 max_length = 20,
1969 validators=[VnsDhcpModeValidator()],
1970 default='flood-if-unknown')
1971
1972 dhcp_ip = models.CharField(
1973 verbose_name='DHCP IP Address',
1974 help_text='IP Address of DHCP Server',
1975 validators=[ IpValidator() ],
1976 max_length=15,
1977 blank=True,
1978 null=True)
1979
1980 broadcast = models.CharField(
1981 verbose_name = "Broadcast (non ARP/DHCP) Config Mode",
1982 help_text = "Values: always-flood, forward-to-known, drop",
1983 max_length = 20,
1984 validators=[VnsBroadcastModeValidator()],
1985 default='forward-to-known')
1986
1987 #
1988 # end fields ----------------------------------------
1989
1990 def __unicode__(self):
1991 return self.id
1992
1993 def delete(self):
1994 #default VNS can't be deleted
1995 if self.id=='default|default':
1996 raise ValidationError("Default VNS can't be deleted")
1997 #while address space still exist, address space default vns can't be deleted
1998 #for fat tire, relationship between address space and tenant are unclear yet, the following part may need revisit
1999 suffix = '-default'
2000 if self.vnsname.endswith(suffix):
2001 print self.vnsname
2002 address_space_name = self.vnsname[:-len(suffix)]
2003 error=False
2004 try:
2005 self.vns_address_space = AddressSpace.objects.get(name = address_space_name)
2006 error=True
2007 except Exception, e:
2008 pass
2009 if error:
2010 raise ValidationError('vns %s is the default VNS of address space: %s, can not be deleted ' %
2011 (self.vnsname,address_space_name))
2012 super(VNS, self).delete()
2013 # manage a magic association between vns names and
2014 # address space for vns's which end in -default
2015 def validate_unique(self, exclude = None):
2016 # Invoke the default validator; error out if the vns already exists
2017 #for fat tire, relationship between address space and tenant are unclear yet, the following part may need revisit
2018 super(VNS, self).validate_unique(exclude)
2019 suffix = '-default'
2020 if not 'vns_address_space' in exclude:
2021 if self.vns_address_space:
2022 if self.vnsname.endswith(suffix):
2023 if str(self.vns_address_space) != self.vnsname[:-len(suffix)]:
2024 raise ValidationError('vns names %s ending in -default '
2025 'must have address_space names with the same prefix: %s '
2026 % (self.vnsname, self.vns_address_space))
2027 elif self.vnsname.endswith(suffix):
2028 address_space_name = self.vnsname[:-len(suffix)]
2029 try:
2030 self.vns_address_space = AddressSpace.objects.get(name = address_space_name)
2031 except Exception, e:
2032 print e
2033 if self.vns_address_space == None:
2034 raise ValidationError('vns %s has no matching address-space %s ' %
2035 (self.vnsname, address_space_name))
2036
2037 class CassandraSettings:
2038 COMPOUND_KEY_FIELDS = ('tenant', 'vnsname')
2039
2040 class Rest:
2041 NAME = 'vns-definition'
2042 FIELD_INFO = (
2043 {'name': 'vns_address_space', 'rest_name': 'address-space'},
2044 {'name': 'arp_mode', 'rest_name': 'arp-mode'},
2045 {'name': 'dhcp_mode', 'rest_name': 'dhcp-mode'},
2046 {'name': 'dhcp_ip', 'rest_name': 'dhcp-ip'},
2047 )
2048
2049#
2050# ------------------------------------------------------------
2051# An interface rule on a VNS
2052
2053class VNSInterfaceRule(models.Model):
2054 rule_max_length = 32
2055
2056 #
2057 # fields ----------------------------------------
2058
2059 vns = models.ForeignKey(
2060 VNS,
2061 verbose_name='VNS ID')
2062
2063 rule = models.CharField(
2064 verbose_name='VNS Rule ID',
2065 max_length=rule_max_length)
2066
2067 description = models.CharField(
2068 verbose_name='Description',
2069 help_text="Description of rule",
2070 max_length=128,
2071 blank=True,
2072 null=True)
2073
2074 vlan_tag_on_egress = models.BooleanField(
2075 verbose_name='Egress Vlan Tagging',
2076 help_text='Tag with VLAN at egress point (default is False)',
2077 default=False)
2078
2079 allow_multiple = models.BooleanField(
2080 verbose_name='Allow Multiple',
2081 help_text='If this interface allows hosts to be on multiple VNS (default is False)',
2082 default=False)
2083
2084 active = models.BooleanField(
2085 verbose_name='Active',
2086 help_text='If this interface is active (default is True)',
2087 default=True)
2088
2089 priority = models.IntegerField(
2090 verbose_name='Priority',
2091 help_text='Priority for this interface rule (higher numbers are higher priority)',
2092 default = 32768,
2093 validators=[RangeValidator(0, 65535)])
2094
2095 mac = models.CharField(
2096 verbose_name="MAC Address",
2097 help_text='MAC Address or host alias',
2098 max_length=17,
2099 validators = [validate_mac_address],
2100 blank=True,
2101 null=True)
2102
2103 ip_subnet = models.CharField(
2104 verbose_name="IP Subnet",
2105 help_text='IP address or subnet (e.g. 192.168.1.1 or 192.168.1.0/24)',
2106 max_length=31,
2107 validators = [CidrValidator(False)],
2108 blank=True,
2109 null=True)
2110
2111 switch = models.CharField(
2112 verbose_name='Switch DPID',
2113 max_length= Switch.switch_id_length,
2114 help_text='Switch DPID or switch alias',
2115 validators=[ validate_dpid ],
2116 null=True,
2117 blank=True)
2118
2119 ports = models.CharField(
2120 verbose_name="Port Range Spec",
2121 help_text='Port range (e.g. C12 or B1,A22-25)',
2122 max_length=256,
2123 validators = [PortRangeSpecValidator()],
2124 blank=True,
2125 null=True)
2126
2127 vlans = models.CharField(
2128 verbose_name="VLAN Range Spec",
2129 help_text="VLAN(s) (e.g. 5 or 5-10,4010-4050)",
2130 max_length=256,
2131 validators = [VLANRangeSpecValidator()],
2132 blank=True,
2133 null=True)
2134
2135 tags = models.CharField(
2136 verbose_name="Tag Spec",
2137 help_text="Tag values (e.g. namespace.tagname=value)",
2138 max_length=256,
2139 validators = [TagSpecValidator()],
2140 blank=True,
2141 null=True)
2142
2143
2144 #
2145 # end fields ----------------------------------------
2146
2147 def __unicode__(self):
2148 return self.id
2149
2150 class CassandraSettings:
2151 COMPOUND_KEY_FIELDS = ('vns', 'rule')
2152
2153 class Rest:
2154 NAME = 'vns-interface-rule'
2155 FIELD_INFO = (
2156 {'name': 'description', 'rest_name': 'description'},
2157 {'name': 'allow_multiple', 'rest_name': 'allow-multiple'},
2158 {'name': 'active', 'rest_name': 'active'},
2159 {'name': 'priority', 'rest_name': 'priority'},
2160 {'name': 'mac', 'rest_name': 'mac'},
2161 {'name': 'ip_subnet', 'rest_name': 'ip-subnet'},
2162 {'name': 'switch', 'rest_name': 'switch'},
2163 {'name': 'ports', 'rest_name': 'ports'},
2164 {'name': 'vlans', 'rest_name': 'vlans'},
2165 {'name': 'tags', 'rest_name': 'tags'},
2166 {'name': 'vlan_tag_on_egress', 'rest_name': 'vlan-tag-on-egress'},
2167 )
2168
2169#
2170# ------------------------------------------------------------
2171
2172class VNSInterfaceConfig(models.Model):
2173 name_max_length = 32
2174 #
2175 # fields ----------------------------------------
2176
2177 vns = models.ForeignKey(
2178 VNS,
2179 verbose_name='VNS ID')
2180
2181 interface = models.CharField(
2182 verbose_name='VNS Interface Name',
2183 max_length=name_max_length,
2184 validators = [VnsInterfaceNameValidator()])
2185
2186 rule = models.ForeignKey(
2187 VNSInterfaceRule,
2188 verbose_name='VNS Rule ID',
2189 blank=True,
2190 null=True)
2191
2192 #
2193 # end fields ----------------------------------------
2194
2195 def __unicode__(self):
2196 return self.id
2197
2198 class CassandraSettings:
2199 COMPOUND_KEY_FIELDS = ('vns', 'interface')
2200
2201 class Rest:
2202 NAME = 'vns-interface-config'
2203 FIELD_INFO = (
2204 {'name': 'rule', 'rest_name': 'rule'},
2205 )
2206
2207
2208#
2209# ------------------------------------------------------------
2210
2211class VNSAcl(models.Model):
2212 name_max_length=32
2213 #
2214 # fields ----------------------------------------
2215
2216 vns = models.ForeignKey(
2217 VNS,
2218 verbose_name='VNS ID')
2219
2220 name = models.CharField(
2221 help_text='Acl Name',
2222 validators=[VnsAclNameValidator()],
2223 max_length=name_max_length)
2224
2225 priority = models.IntegerField(
2226 verbose_name='Priority',
2227 help_text='Priority for this ACL (higher numbers are higher priority)',
2228 default = 32768,
2229 validators=[RangeValidator(0, 65535)])
2230
2231 description = models.CharField(
2232 verbose_name='Description',
2233 help_text="Description of the ACL",
2234 max_length=128,
2235 blank=True,
2236 null=True)
2237
2238 #
2239 # end fields ----------------------------------------
2240
2241 class CassandraSettings:
2242 COMPOUND_KEY_FIELDS = ('vns', 'name')
2243
2244 def __unicode__(self):
2245 return self.id
2246
2247 class Rest:
2248 NAME = 'vns-access-list'
2249 FIELD_INFO = (
2250 {'name': 'name', 'rest_name': 'name'},
2251 {'name': 'priority', 'rest_name': 'priority'},
2252 {'name': 'description', 'rest_name': 'description'},
2253 )
2254
2255#
2256# ------------------------------------------------------------
2257
2258class VNSAclEntry(models.Model):
2259 #
2260 # fields ----------------------------------------
2261
2262 rule = models.CharField(
2263 help_text='Rule ID',
2264 validators=[VnsRuleNameValidator()],
2265 max_length=15)
2266
2267 vns_acl = models.ForeignKey(
2268 VNSAcl,
2269 verbose_name='VNS Acl name')
2270
2271 action = models.CharField(
2272 verbose_name='permit or deny',
2273 help_text="'permit' or 'deny'",
2274 max_length=16,
2275 validators=[ VnsAclEntryActionValidator() ])
2276
2277 type = models.CharField(
2278 verbose_name='mac/ip/<0-255>/udp/tcp/icmp',
2279 help_text="ACLtype either mac or ip or udp or tcp or icmp or ip-protocol-type",
2280 max_length=16)
2281
2282 src_ip = models.CharField(
2283 verbose_name='Source IP',
2284 help_text='Source IP Address to match',
2285 validators=[ IpValidator() ],
2286 max_length=15,
2287 blank=True,
2288 null=True)
2289
2290 src_ip_mask = models.CharField(
2291 verbose_name='Source IP Mask',
2292 help_text='Mask to match source IP',
2293 validators=[ IpValidator() ],
2294 max_length=15,
2295 blank=True,
2296 null=True)
2297
2298 src_tp_port_op = models.CharField(
2299 verbose_name='Source Port comparison op',
2300 help_text='Compare with tcp/udp port eq/neq/any',
2301 max_length=5,
2302 blank=True,
2303 null=True)
2304
2305 src_tp_port = models.IntegerField(
2306 verbose_name='Source UDP/TCP Port',
2307 help_text='Source port value to compare',
2308 validators=[RangeValidator(0, 65535)],
2309 blank=True,
2310 null=True)
2311
2312 dst_ip = models.CharField(
2313 verbose_name='Destination IP',
2314 help_text='Destination IP Address to match',
2315 validators=[ IpValidator() ],
2316 max_length=15,
2317 blank=True,
2318 null=True)
2319
2320 dst_ip_mask = models.CharField(
2321 verbose_name='Destination IP Mask',
2322 help_text='Mask to match destination IP',
2323 validators=[ IpValidator() ],
2324 max_length=15,
2325 blank=True,
2326 null=True)
2327
2328 dst_tp_port_op = models.CharField(
2329 verbose_name='Destination Port comparison op',
2330 help_text='Compare with tcp/udp port eq/neq/any',
2331 max_length=3,
2332 blank=True,
2333 null=True)
2334
2335 dst_tp_port = models.IntegerField(
2336 verbose_name='Destination UDP/TCP Port',
2337 help_text='Destination port value to compare',
2338 validators=[RangeValidator(0, 65535)],
2339 blank=True,
2340 null=True)
2341
2342 icmp_type = models.IntegerField(
2343 verbose_name='ICMP Type',
2344 help_text='Matching ICMP type icmp (blank matches all)',
2345 validators=[RangeValidator(0, 255)],
2346 blank=True,
2347 null=True)
2348
2349 src_mac = models.CharField(
2350 verbose_name="Source MAC Address",
2351 help_text="Colon separated hex string (blank matches all)",
2352 max_length=17,
2353 validators = [validate_mac_address],
2354 blank=True,
2355 null=True)
2356
2357 dst_mac = models.CharField(
2358 verbose_name="Destination MAC Address",
2359 help_text="Colon separated hex string (blank matches all)",
2360 max_length=17,
2361 validators = [validate_mac_address],
2362 blank=True,
2363 null=True)
2364
2365 ether_type = models.IntegerField(
2366 verbose_name='Ethernet Packet Type',
2367 help_text='Standard ether type (blank matches all)',
2368 validators=[RangeValidator(1536, 65535)],
2369 blank=True,
2370 null=True)
2371
2372 vlan = models.IntegerField(
2373 verbose_name="VLAN ID",
2374 help_text='Standard ether type (blank matches all)',
2375 blank=True,
2376 null=True,
2377 validators = [ RangeValidator(0, 4095) ])
2378
2379 #
2380 # end fields ----------------------------------------
2381
2382 def __unicode__(self):
2383 return self.id
2384
2385 class CassandraSettings:
2386 COMPOUND_KEY_FIELDS = ('vns_acl', 'rule')
2387
2388 def validate_unique(self, exclude = None):
2389 #
2390 # there are three types of entries:
2391 # - mac based rules
2392 # - ip based rules
2393 # - tcp/udp based rules
2394 #
2395 # verify that for each rules, unexpected fields are not
2396 # populated
2397
2398 if self.type == 'mac':
2399 if self.src_ip or self.src_ip_mask:
2400 raise ValidationError("vns-access-list-entry mac rule:"
2401 " src-ip/src-ip-mask specified"
2402 "(ought to be null)")
2403 if self.dst_ip or self.dst_ip_mask:
2404 raise ValidationError("vns-access-list-entry mac rule:"
2405 " dst-ip/dst-ip-mask specified "
2406 "(ought to be null)")
2407 if self.src_tp_port_op or self.src_tp_port:
2408 raise ValidationError("vns-access-list-entry mac rule:"
2409 " src-tp-port-op/src-to-port specified "
2410 "(ought to be null)")
2411 if self.dst_tp_port_op or self.dst_tp_port:
2412 raise ValidationError("vns-access-list-entry mac rule:"
2413 " dst-tp-port-op/dst-to-port specified "
2414 "(ought to be null)")
2415 if self.icmp_type:
2416 raise ValidationError("vns-access-list-entry mac rule:"
2417 " icmp_type specified "
2418 "(ought to be null)")
2419 elif self.type == 'ip' or re.match('[\d]+', self.type) or \
2420 self.type == 'icmp':
2421 if (self.src_tp_port_op != None or self.src_tp_port != None) and \
2422 ((self.src_tp_port_op == None) or (self.src_tp_port == None)):
2423 raise ValidationError("vns-access-list-entry ip rule:"
2424 " src-tp-port-op/src-to-port specified "
2425 "(both or neither)")
2426 if (self.dst_tp_port_op != None or self.dst_tp_port != None) and \
2427 ((self.dst_tp_port_op == None) or (self.dst_tp_port == None)):
2428 raise ValidationError("vns-access-list-entry ip rule:"
2429 " dst-tp-port-op/dst-to-port specified "
2430 "(both or neither)")
2431 if self.src_mac or self.dst_mac:
2432 raise ValidationError("vns-access-list-entry ip rule:"
2433 " src_mac/dst_mac specified "
2434 "(ought to be null)")
2435 if self.ether_type or self.vlan:
2436 raise ValidationError("vns-access-list-entry ip rule:"
2437 " ether-type/vlan specified "
2438 "(ought to be null)")
2439
2440 elif self.type == 'tcp' or self.type == 'udp':
2441 if self.src_mac or self.dst_mac:
2442 raise ValidationError("vns-access-list-entry ip rule:"
2443 " src_mac/dst_mac specified "
2444 "(ought to be null)")
2445 if self.ether_type or self.vlan:
2446 raise ValidationError("vns-access-list-entry ip rule:"
2447 " ether-type/vlan specified "
2448 "(ought to be null)")
2449
2450
2451 class Rest:
2452 NAME = 'vns-access-list-entry'
2453 FIELD_INFO = (
2454 {'name': 'vns_acl', 'rest_name': 'vns-access-list'},
2455 {'name': 'src_ip', 'rest_name': 'src-ip'},
2456 {'name': 'src_ip_mask', 'rest_name': 'src-ip-mask'},
2457 {'name': 'dst_ip', 'rest_name': 'dst-ip'},
2458 {'name': 'dst_ip_mask', 'rest_name': 'dst-ip-mask'},
2459 {'name': 'src_tp_port_op', 'rest_name': 'src-tp-port-op'},
2460 {'name': 'src_tp_port', 'rest_name': 'src-tp-port'},
2461 {'name': 'dst_tp_port_op', 'rest_name': 'dst-tp-port-op'},
2462 {'name': 'dst_tp_port', 'rest_name': 'dst-tp-port'},
2463 {'name': 'icmp_type', 'rest_name': 'icmp-type'},
2464 {'name': 'src_mac', 'rest_name': 'src-mac'},
2465 {'name': 'dst_mac', 'rest_name': 'dst-mac'},
2466 {'name': 'ether_type', 'rest_name': 'ether-type'},
2467 )
2468
2469#
2470# ------------------------------------------------------------
2471
2472class VNSInterfaceAcl(models.Model):
2473 in_out_length = 4
2474
2475 #
2476 # fields ----------------------------------------
2477
2478 vns_acl = models.ForeignKey(
2479 VNSAcl,
2480 verbose_name='VNS Acl name')
2481
2482 vns_interface = models.ForeignKey(
2483 VNSInterfaceConfig,
2484 verbose_name='VNS Interface ID',
2485 help_text='[vns id]|[interface long name]')
2486
2487 in_out = models.CharField(
2488 verbose_name='in/out',
2489 help_text='Match on packet input or output',
2490 validators=[VnsInterfaceAclInOutValidator()],
2491 max_length=in_out_length,
2492 )
2493
2494 #
2495 # end fields ----------------------------------------
2496
2497 def __unicode__(self):
2498 return self.id
2499
2500 class CassandraSettings:
2501 COMPOUND_KEY_FIELDS = ('vns_interface', 'vns_acl', 'in_out')
2502
2503 def validate_unique(self, exclude = None):
2504 acl_parts = str(self.vns_acl).split('|')
2505 intf_parts = str(self.vns_interface).split('|')
2506 # validate two vns parts
2507 if acl_parts[0] != intf_parts[0]:
2508 raise ValidationError("acl's vns %s doen't match interface vns %s" %
2509 (acl_parts[0], intf_parts[0]))
2510 error = False
2511 try:
2512 exists = VNSInterfaceAcl.objects.get(vns_interface=self.vns_interface, in_out=self.in_out)
2513 if exists:
2514 if exists.vns_acl != self.vns_acl:
2515 error = True
2516 except:
2517 pass
2518 if error:
2519 raise ValidationError("Interface %s already has an ACL in the %s direction, only one ACL per direction allowed" % (self.vns_interface, self.in_out))
2520
2521 class Rest:
2522 NAME = 'vns-interface-access-list'
2523 FIELD_INFO = (
2524 {'name': 'vns_acl', 'rest_name': 'vns-access-list'},
2525 {'name': 'vns_interface', 'rest_name': 'vns-interface'},
2526 {'name': 'in_out', 'rest_name': 'in-out'},
2527 )
2528
2529#
2530# ------------------------------------------------------------
2531# A virtual router interface separation
2532
2533class VirtualRouterInterface (models.Model):
2534
2535 id_max_length = 64
2536 #
2537 # fields ----------------------------------------
2538 virtual_router = models.ForeignKey(
2539 VirtualRouter,
2540 verbose_name='Virtual Router ID')
2541 #
2542 # Unique name of the interface
2543 #
2544 vriname = models.CharField(
2545 verbose_name = 'Interface Name',
2546 help_text = 'A unique name for a virtual router interface',
2547 validators = [ GeneralNameValidator() ],
2548 max_length = id_max_length)
2549 #
2550 # Origin of this configured item
2551 #
2552 origin = models.CharField(
2553 verbose_name = "Origin",
2554 help_text = "Values: cli, rest, other packages",
2555 max_length = 64, # in future we might use SW GUIDs for this field
2556 blank = True,
2557 null = True)
2558 #
2559 # Whether the configuration is active ? By default, it is active
2560 # Used to disable the configuration without having to delete the entire
2561 # interface configuration construct.
2562 #
2563 active = models.BooleanField(
2564 verbose_name = 'Active',
2565 help_text = 'Is this interface active (default is True)',
2566 default = True)
2567 vns_connected = models.ForeignKey(
2568 VNS,
2569 verbose_name='VNS connected to',
2570 blank =True,
2571 null =True)
2572 router_connected = models.ForeignKey(
2573 VirtualRouter,
2574 related_name='router_connected',
2575 verbose_name='Virtual Router connected to',
2576 blank =True,
2577 null =True)
2578
2579 #
2580 # end fields ----------------------------------------
2581
2582 def __unicode__ (self):
2583 return self.id
2584
2585 def validate_unique(self, exclude = None):
2586 def is_set(value):
2587 if value != None and value != '':
2588 return True
2589
2590 # for vns connection, verify that only the VNSs under the same tenant can be connected
2591 error=False
2592 if not 'vns_connected' in exclude:
2593 if is_set(self.vns_connected):
2594 tenant_vns_parts = str(self.vns_connected).split('|')
2595 tenant_router_parts = str(self.virtual_router).split('|')
2596 if tenant_vns_parts[0] != tenant_router_parts[0]:
2597 raise ValidationError(" VNS %s belongs to tenant %s, doesn't match virtual router tenant %s" %
2598 (tenant_vns_parts[1],tenant_vns_parts[0], tenant_router_parts[0]))
2599 # verify there can only be one connection for one VNS
2600 try:
2601 exists = VirtualRouterInterface.objects.get(virtual_router = self.virtual_router, vns_connected=self.vns_connected)
2602 if exists:
2603 if exists.vriname!=self.vriname:
2604 error=True
2605 except:
2606 pass
2607 if error:
2608 raise ValidationError(" VNS %s has been connected, multiple connections is not allowed" % self.vns_connected)
2609 error = False
2610 # for router connection, verify that the same virtual router as myself can't be connected
2611 if not 'router_connected' in exclude:
2612 if is_set(self.router_connected):
2613 tenant_router_parts = str(self.router_connected).split('|')
2614 tenant_myrouter_parts = str(self.virtual_router).split('|')
2615 if tenant_router_parts[0] == tenant_myrouter_parts[0]:
2616 raise ValidationError(" Local loop conncetion is not allowed.")
2617 # verify there can only be one connection for one virtual router
2618 try:
2619 exists = VirtualRouterInterface.objects.get(virtual_router = self.virtual_router,router_connected=self.router_connected)
2620 if exists:
2621 if exists.vriname!=self.vriname:
2622 error=True
2623 except:
2624 pass
2625 if error:
2626 raise ValidationError(" Virtual Router %s has been connected, multiple connections is not allowed" % self.router_connected)
2627
2628 class CassandraSettings:
2629 COMPOUND_KEY_FIELDS = ('virtual_router', 'vriname')
2630
2631 class Rest:
2632 NAME = 'virtualrouter-interface'
2633 FIELD_INFO = (
2634 {'name': 'vns_connected', 'rest_name': 'vns-connected'},
2635 {'name': 'router_connected', 'rest_name': 'router-connected'},
2636 {'name': 'virtual_router', 'rest_name': 'virtual-router'},
2637
2638 )
2639
2640#
2641# ------------------------------------------------------------
2642# A virtual router interface address pool separation
2643
2644class VRInterfaceIpAddressPool (models.Model):
2645
2646 id_max_length = 64
2647 #
2648 # fields ----------------------------------------
2649 virtual_router_interface = models.ForeignKey(
2650 VirtualRouterInterface,
2651 verbose_name='Virtual Router Interface ID')
2652 #
2653 # Origin of this configured item
2654 #
2655 origin = models.CharField(
2656 verbose_name = "Origin",
2657 help_text = "Values: cli, rest, other packages",
2658 max_length = 64,
2659 blank = True,
2660 null = True)
2661 ip_address = models.CharField(
2662 verbose_name='Source IP',
2663 help_text='Interface IP Address',
2664 validators=[ IpValidator() ],
2665 max_length=15,
2666 blank=True,
2667 null=True)
2668 subnet_mask = models.CharField(
2669 verbose_name='Subnet IP Mask',
2670 validators=[ IpMaskValidator() ],
2671 max_length=15,
2672 blank=True,
2673 null=True)
2674
2675 #
2676 # end fields ----------------------------------------
2677
2678 def __unicode__ (self):
2679 return self.id
2680
2681 class CassandraSettings:
2682 COMPOUND_KEY_FIELDS = ('virtual_router_interface', 'ip_address')
2683
2684 class Rest:
2685 NAME = 'interface-address-pool'
2686 FIELD_INFO = (
2687 {'name': 'virtual_router_interface', 'rest_name': 'virtual-router-interface'},
2688 {'name': 'ip_address', 'rest_name': 'ip-address'},
2689 {'name': 'subnet_mask', 'rest_name': 'subnet-mask'},
2690 )
2691
2692
2693#
2694# ------------------------------------------------------------
2695
2696class VirtualRouterGWPool (models.Model):
2697
2698 id_max_length = 64
2699 #
2700 # fields ----------------------------------------
2701 virtual_router = models.ForeignKey(
2702 VirtualRouter,
2703 verbose_name='Virtual Router ID')
2704 #
2705 # Unique name of the gateway pool
2706 #
2707 vrgwname = models.CharField(
2708 verbose_name = 'Gateway Pool Name',
2709 help_text = 'A unique name for a virtual router gateway pool',
2710 validators = [ GeneralNameValidator() ],
2711 max_length = id_max_length)
2712
2713 #
2714 # end fields ----------------------------------------
2715
2716 def __unicode__ (self):
2717 return self.id
2718
2719 def validate_unique(self, exclude = None):
2720 def is_set(value):
2721 if value != None and value != '':
2722 return True
2723
2724 class CassandraSettings:
2725 COMPOUND_KEY_FIELDS = ('virtual_router', 'vrgwname')
2726
2727 class Rest:
2728 NAME = 'virtualrouter-gwpool'
2729 FIELD_INFO = (
2730 {'name': 'virtual_router', 'rest_name': 'virtual-router'},
2731 )
2732
2733#
2734# ------------------------------------------------------------
2735# A virtual router gateway address pool separation
2736
2737class VRGatewayIpAddressPool (models.Model):
2738
2739 id_max_length = 64
2740 #
2741 # fields ----------------------------------------
2742 virtual_router_gwpool = models.ForeignKey(
2743 VirtualRouterGWPool,
2744 verbose_name='Virtual Router Gateway Pool ID')
2745 ip_address = models.CharField(
2746 verbose_name='Gateway IP',
2747 help_text='Gateway IP Address',
2748 validators=[ IpValidator() ],
2749 max_length=15,
2750 blank=True,
2751 null=True)
2752
2753 #
2754 # end fields ----------------------------------------
2755
2756 def __unicode__ (self):
2757 return self.id
2758
2759 class CassandraSettings:
2760 COMPOUND_KEY_FIELDS = ('virtual_router_gwpool', 'ip_address')
2761
2762 class Rest:
2763 NAME = 'gateway-address-pool'
2764 FIELD_INFO = (
2765 {'name': 'virtual_router_gwpool', 'rest_name': 'virtual-router-gwpool'},
2766 {'name': 'ip_address', 'rest_name': 'ip-address'},
2767 )
2768
2769class VirtualRoutingRule (models.Model):
2770
2771 id_max_length = 64
2772 #
2773 # fields ----------------------------------------
2774 virtual_router = models.ForeignKey(
2775 VirtualRouter,
2776 verbose_name='Virtual Router ID')
2777 #
2778 # Origin of this configured item
2779 #
2780 origin = models.CharField(
2781 verbose_name = "Origin",
2782 help_text = "Values: cli, rest, other packages",
2783 max_length = 64,
2784 blank = True,
2785 null = True)
2786 src_host = models.ForeignKey(
2787 HostConfig,
2788 verbose_name='source Host ID',
2789 help_text='Source Host ID to match',
2790 blank =True,
2791 null =True)
2792 src_tenant = models.ForeignKey(
2793 Tenant,
2794 verbose_name='source tenant ID',
2795 help_text='Source tenant ID to match',
2796 blank =True,
2797 null =True)
2798 src_vns = models.ForeignKey(
2799 VNS,
2800 verbose_name='source VNS ID',
2801 help_text='Source VNS ID to match',
2802 blank =True,
2803 null =True)
2804 src_ip = models.CharField(
2805 verbose_name='Source IP',
2806 help_text='Source IP Address to match',
2807 validators=[ IpValidator() ],
2808 max_length=15,
2809 blank=True,
2810 null=True)
2811 src_ip_mask = models.CharField(
2812 verbose_name='Source IP Mask',
2813 help_text='Mask to match source IP',
2814 validators=[ IpMaskValidator() ],
2815 max_length=15,
2816 blank=True,
2817 null=True)
2818 dst_host = models.ForeignKey(
2819 HostConfig,
2820 verbose_name='Destination Host ID',
2821 help_text='Destination Host ID to match',
2822 related_name='dest_host',
2823 blank =True,
2824 null =True)
2825 dst_tenant = models.ForeignKey(
2826 Tenant,
2827 verbose_name='Destination tenant ID',
2828 related_name='dest_tenant',
2829 blank =True,
2830 null =True)
2831 dst_vns = models.ForeignKey(
2832 VNS,
2833 verbose_name='Destination VNS ID',
2834 related_name='dest_vns',
2835 blank =True,
2836 null =True)
2837 dst_ip = models.CharField(
2838 verbose_name='Destination IP',
2839 help_text='Destination IP Address to match',
2840 validators=[ IpValidator() ],
2841 max_length=15,
2842 blank=True,
2843 null=True)
2844 dst_ip_mask = models.CharField(
2845 verbose_name='Destination IP Mask',
2846 help_text='Mask to match destination IP',
2847 validators=[ IpMaskValidator() ],
2848 max_length=15,
2849 blank=True,
2850 null=True)
2851 outgoing_intf = models.ForeignKey(
2852 VirtualRouterInterface,
2853 verbose_name='Outgoing Interface',
2854 blank =True,
2855 null =True)
2856 gateway_pool = models.ForeignKey(
2857 VirtualRouterGWPool,
2858 verbose_name='Gateway pool',
2859 blank =True,
2860 null =True)
2861 nh_ip = models.CharField(
2862 verbose_name='Next Hop IP',
2863 help_text='Next Hop IP Address',
2864 validators=[ IpValidator() ],
2865 max_length=15,
2866 blank=True,
2867 null=True)
2868 action = models.CharField(
2869 verbose_name='permit or deny',
2870 help_text="'permit' or 'deny'",
2871 default='permit',
2872 max_length=16,
2873 validators=[ VnsAclEntryActionValidator() ])
2874 #
2875 # end fields ----------------------------------------
2876
2877 def __unicode__ (self):
2878 return self.id
2879
2880 def validate_unique(self, exclude = None):
2881 def is_set(value):
2882 if value != None and value != '':
2883 return True
2884 #verify the outgoing interface can only be on the local virtual router interface
2885 if not 'outgoing_intf' in exclude:
2886 if is_set(self.outgoing_intf):
2887 router_parts = str(self.outgoing_intf).split('|')
2888 myrouter_parts = str(self.virtual_router).split('|')
2889 if (router_parts[0] != myrouter_parts[0]) or (router_parts[1] != myrouter_parts[1]):
2890 raise ValidationError(" outgoing interface has to be local to virtual router: %s|%s" %
2891 (myrouter_parts[0],myrouter_parts[1]))
2892 #verify the gateway pool belongs to the local virtual router
2893 if not 'gateway_pool' in exclude:
2894 if is_set(self.gateway_pool):
2895 router_parts = str(self.gateway_pool).split('|')
2896 myrouter_parts = str(self.virtual_router).split('|')
2897 if (router_parts[0] != myrouter_parts[0]) or (router_parts[1] != myrouter_parts[1]):
2898 raise ValidationError(" gateway pool has to be local to virtual router: %s|%s" %
2899 (myrouter_parts[0],myrouter_parts[1]))
2900
2901 class CassandraSettings:
2902 COMPOUND_KEY_FIELDS = ('virtual_router', 'src_host', 'src_tenant','src_vns','src_ip','src_ip_mask', 'dst_host', 'dst_tenant','dst_vns','dst_ip','dst_ip_mask')
2903
2904 class Rest:
2905 NAME = 'virtualrouter-routingrule'
2906 FIELD_INFO = (
2907 {'name': 'virtual_router', 'rest_name': 'virtual-router'},
2908 {'name': 'src_tenant', 'rest_name': 'src-tenant'},
2909 {'name': 'dst_tenant', 'rest_name': 'dst-tenant'},
2910 {'name': 'src_vns', 'rest_name': 'src-vns'},
2911 {'name': 'src_ip', 'rest_name': 'src-ip'},
2912 {'name': 'src_ip_mask', 'rest_name': 'src-ip-mask'},
2913 {'name': 'dst_ip', 'rest_name': 'dst-ip'},
2914 {'name': 'dst_ip_mask', 'rest_name': 'dst-ip-mask'},
2915 {'name': 'nh_ip', 'rest_name': 'nh-ip'},
2916 {'name': 'outgoing_intf', 'rest_name': 'outgoing-intf'},
2917 {'name': 'dst_host', 'rest_name': 'dst-host'},
2918 {'name': 'src_host', 'rest_name': 'src-host'},
2919 {'name': 'dst_vns', 'rest_name': 'dst-vns'},
2920 {'name': 'gateway_pool', 'rest_name': 'gateway-pool'},
2921 )
srikanth116e6e82014-08-19 07:22:37 -07002922#
2923# ------------------------------------------------------------
Srikanth Vavilapalli22e58e92014-10-16 14:04:48 -07002924"""
srikanth116e6e82014-08-19 07:22:37 -07002925class Tag(models.Model):
2926 namespace_length = 64
2927 name_length = 64
2928 value_length = 64
2929
2930 #
2931 # fields ----------------------------------------
2932
2933 namespace = models.CharField(
2934 verbose_name='Tag Namespace',
2935 help_text="Namespace of the tag",
2936 max_length=namespace_length)
2937
2938 name = models.CharField(
2939 verbose_name='Tag Name',
2940 help_text="Name of the tag",
2941 max_length=name_length)
2942
2943 value = models.CharField(
2944 verbose_name='Tag Value',
2945 help_text="Value of the tag",
2946 max_length=value_length)
2947
2948 persist = models.BooleanField(
2949 verbose_name='persist',
2950 help_text='For any cli configured tag, include in running-config',
2951 default=True)
2952
2953 #
2954 # end fields ----------------------------------------
2955
2956 def __unicode__(self):
2957 return self.id
2958
2959 class CassandraSettings:
2960 COMPOUND_KEY_FIELDS = ('namespace', 'name', 'value')
2961
2962 class Rest:
2963 NAME = 'tag'
2964
2965#
2966# ------------------------------------------------------------
2967
2968class TagMapping(models.Model):
2969 host_id_length = 17
2970 switch_id_length = 23
2971 if_name_len = 32
2972 vlan_str_len = 4
2973 #
2974 # fields ----------------------------------------
2975
2976 tag = models.ForeignKey(
2977 Tag)
2978
2979 mac = models.CharField(
2980 verbose_name="MAC Address",
2981 max_length=host_id_length,
2982 validators = [validate_mac_address],
2983 default="",
2984 blank=True)
2985
2986 vlan = models.CharField(
2987 verbose_name='VLAN',
2988 max_length=vlan_str_len,
2989 help_text='VLAN Number, in the range of 1-4095. 4095 means untagged',
2990 validators=[VlanStringValidator()],
2991 default="",
2992 blank=True)
2993
2994 dpid = models.CharField(
2995 verbose_name='Switch DPID',
2996 help_text='Switch DPID - 64-bit hex separated by :',
2997 max_length=switch_id_length,
2998 validators=[ validate_dpid ],
2999 default="",
3000 blank=True)
3001
3002 ifname = models.CharField(
3003 verbose_name='If Name regular expression',
3004 max_length=if_name_len,
3005 default="",
3006 validators=[ SafeForPrimaryKeyValidator() ],
3007 blank=True)
3008
3009 #
3010 # end fields ----------------------------------------
3011
3012 def __unicode__(self):
3013 return self.id
3014
3015 class CassandraSettings:
3016 COMPOUND_KEY_FIELDS = ('tag', 'mac', 'vlan', 'dpid', 'ifname')
3017
3018 def validate_unique(self, exclude = None):
3019 if self.mac != '':
3020 self.mac = self.mac.lower()
3021
3022 if self.dpid != '':
3023 self.dpid = self.dpid.lower()
3024
3025 # don't allow all default values for the association
3026 if self.mac == '' and self.vlan == '' and \
3027 self.dpid == '' and self.ifname == '':
3028 raise ValidationError("Match without any matching fields")
3029
3030 class Rest:
3031 NAME = 'tag-mapping'
Srikanth Vavilapalli22e58e92014-10-16 14:04:48 -07003032"""
srikanth116e6e82014-08-19 07:22:37 -07003033#
3034# ------------------------------------------------------------
srikanth116e6e82014-08-19 07:22:37 -07003035class TechSupportConf(models.Model):
3036
3037 #
3038 # fields ----------------------------------------
3039
3040 cmd_type = models.CharField(
3041 verbose_name='Type of command',
3042 help_text='Enter cli or shell',
3043 max_length=32)
3044
3045 cmd = models.CharField(
3046 max_length=256,
3047 verbose_name='Command name',
3048 help_text = 'Command excuted by show tech-support')
3049
3050
3051 #
3052 # end fields ----------------------------------------
3053
3054 def __unicode__(self):
3055 return self.id
3056
3057 class CassandraSettings:
3058 COMPOUND_KEY_FIELDS = ('cmd_type', 'cmd')
3059
3060 class Rest:
3061 NAME = 'tech-support-config'
3062 FIELD_INFO = (
3063 {'name': 'cmd_type', 'rest_name': 'cmd-type'},
3064 )
3065
3066#
3067# ------------------------------------------------------------
3068
3069class TacacsPlusConfig(models.Model):
3070 #
3071 # fields ----------------------------------------
3072
3073 id = models.CharField(
3074 primary_key=True,
3075 verbose_name='tacacs singleton',
3076 default='tacacs',
3077 max_length=16)
3078
3079 tacacs_plus_authn = models.BooleanField(
3080 verbose_name='TACACS+ Authentication Enabled',
3081 help_text='Enable TACACS+ authentication by setting to true',
3082 default=False
3083 )
3084
3085 tacacs_plus_authz = models.BooleanField(
3086 verbose_name='TACACS+ Authorization Enabled',
3087 help_text='Enable TACACS+ authorization by setting to true',
3088 default=False
3089 )
3090
3091 tacacs_plus_acct = models.BooleanField(
3092 verbose_name='TACACS+ Accounting Enabled',
3093 help_text='Enable TACACS+ accounting by setting to true',
3094 default=False
3095 )
3096
3097 local_authn = models.BooleanField(
3098 verbose_name='Local Authentication Enabled',
3099 help_text='Enable local authentication by setting to true',
3100 default=True
3101 )
3102
3103 local_authz = models.BooleanField(
3104 verbose_name='Local Authorization Enabled',
3105 help_text='Enable local authorization by setting to true',
3106 default=True
3107 )
3108
3109 timeout = models.IntegerField(
3110 verbose_name="TACACS+ Server Timeout",
3111 help_text='Set TACACS+ server timeout in seconds',
3112 default=0,
3113 validators=[ RangeValidator(0, 2**16-1) ])
3114
3115 key = models.CharField(
3116 verbose_name='TACACS+ Pre-shared Key',
3117 help_text='pre-shared key to connect to TACACS+ server(s)',
3118 max_length=256,
3119 blank=True,
3120 default="")
3121
3122 #
3123 # end fields ----------------------------------------
3124
3125 class Rest:
3126 NAME = 'tacacs-plus-config'
3127 FIELD_INFO = (
3128 {'name': 'tacacs_plus_authn', 'rest_name': 'tacacs-plus-authn'},
3129 {'name': 'tacacs_plus_authz', 'rest_name': 'tacacs-plus-authz'},
3130 {'name': 'tacacs_plus_acct', 'rest_name': 'tacacs-plus-acct'},
3131 {'name': 'local_authn', 'rest_name': 'local-authn'},
3132 {'name': 'local_authz', 'rest_name': 'local-authz'},
3133 )
3134
3135#
3136# ------------------------------------------------------------
3137
3138class TacacsPlusHost(models.Model):
3139 #
3140 # fields ----------------------------------------
3141
3142 ip = models.CharField(
3143 primary_key=True,
3144 verbose_name='IP Address',
3145 help_text='IP Address for TACACS+ server',
3146 validators=[ IpValidator() ],
3147 max_length=15)
3148
3149 timestamp = models.PositiveIntegerField(
3150 verbose_name='timestamp',
3151 help_text='Timestamp to order the tacacs servers',
3152 default = get_timestamp,
3153 )
3154
3155 key = models.CharField(
3156 verbose_name='TACACS+ Per-host Pre-shared Key',
3157 help_text='pre-shared key to connect to this TACACS+ server',
3158 max_length=256,
3159 blank=True,
3160 default="")
3161
3162 #
3163 # end fields ----------------------------------------
3164
3165 def __unicode__(self):
3166 return "%s" % self.ip
3167
3168 def validate_unique(self, exclude = None):
3169 try:
3170 exists = TacacsPlusHost.objects.get(ip = self.ip)
3171
3172 if exists.timestamp != self.timestamp:
3173 self.timestamp = exists.timestamp
3174 except:
3175 pass
3176
3177 class Rest:
3178 NAME = 'tacacs-plus-host'
3179 FIELD_INFO = (
3180 )
3181
3182#
3183#---------------------------------------------------------
3184
3185class SnmpServerConfig(models.Model):
3186 #
3187 # fields ----------------------------------------
3188
3189 # we just have one row entry in the table to update, so static primary key
3190 id = models.CharField(
3191 primary_key=True,
3192 verbose_name='snmp',
3193 # default='snmp',
3194 max_length=16)
3195
3196 #
3197 # Enable state of the SNMP server/agent on the controller
3198 #
3199 server_enable = models.BooleanField(
3200 verbose_name='SNMP Server enabled',
3201 help_text='Enable SNMP server by setting to true',
3202 default=False
3203 )
3204 #
3205 # Community string for accessing the SNMP server on the controller
3206 #
3207 community = models.CharField(
3208 verbose_name = 'Community String',
3209 help_text = "Community String to access SNMP data",
3210 max_length = 128,
3211 null = True,
3212 blank = True,
3213 )
3214 #
3215 # Location string of the SNMP server on the controller
3216 #
3217 location = models.CharField(
3218 verbose_name = 'System Location',
3219 help_text = "Location information for the controller appliance",
3220 max_length = 128,
3221 null = True,
3222 blank = True
3223 )
3224 #
3225 # Contact string of the SNMP server on the controller
3226 #
3227 contact = models.CharField(
3228 verbose_name = 'System Contact',
3229 help_text = "Contact information for the controller appliance",
3230 max_length = 128,
3231 null = True,
3232 blank = True,
3233 )
3234 #
3235 # end fields ----------------------------------------
3236
3237 def __unicode__(self):
3238 return self.id
3239
3240 def validate_unique(self, exclude = None):
3241 if self.id != 'snmp':
3242 raise ValidationError("Only single snmp record exists")
3243
3244 class Rest:
3245 NAME = 'snmp-server-config'
3246 FIELD_INFO = (
3247 {'name': 'server_enable', 'rest_name': 'server-enable'},
3248 )
3249
3250#
3251# ------------------------------------------------------------
3252
3253class ImageDropUser(models.Model):
3254 #
3255 # fields ----------------------------------------
3256
3257 # we just have one row entry in the table to update, so static primary key
3258 id = models.CharField(
3259 primary_key=True,
3260 verbose_name='imagedropuser',
3261 default='imagedropuser',
3262 max_length=16)
3263
3264 images_user_ssh_key = models.CharField(
3265 verbose_name='Image drop user SSH public key',
3266 help_text='The SSH public RSA key for the images user',
3267 default='',
3268 max_length=600
3269 )
3270 #
3271 # end fields ----------------------------------------
3272
3273 def __unicode__(self):
3274 return self.id
3275
3276 def validate_unique(self, exclude = None):
3277 if self.id != 'imagedropuser':
3278 raise ValidationError("Only single ImageDropUser record exists")
3279
3280 class Rest:
3281 NAME = 'image-drop-user'
3282 FIELD_INFO = (
3283 {'name': 'images_user_ssh_key', 'rest_name': 'images-user-ssh-key'},
3284 )
3285
3286# robv: Commenting out for now. Doesn't work with Cassandra backend
3287#class ConsoleUser(User):
3288#
3289# class Meta:
3290# proxy = True
3291#
3292# class Rest:
3293# NAME = 'user'
Srikanth Vavilapalli669ba8a2014-10-16 11:41:19 -07003294"""