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