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