Структура операционной системы Cisco IOS

Cisco Internetwork Operating System — Межсетевая Операционная Система Cisco

Структура операционной системы Cisco IOS  PDF

Многозадачная операционная система, выполняющая функции сетевой организации, маршрутизации, коммутации и передачи данных. Изначально создана по "мотивам" SUN-Solaris. Номер версии ОС Cisco IOS состоит из трех чисел и нескольких символов a.b(c.d)e, где

***Apple использует торговый знак iOS (название операционной системы iPhone, iPad и iPod touch) по лицензии Cisco.

Cisco 7200       http://www.pluscom.ru/sys-int/data-net/cisco/F7200/


Dynamips — программный эмулятор маршрутизаторов Cisco. Dynamips работает на большинстве Linux-систем, Mac OS X и Windows, при этом позволяет эмуллировать аппаратную часть маршрутизаторов, непосредственно загружая и взаимодействуя с реальными образами Cisco IOS, одним из преимуществ является присоединение эмулируемого маршрутизатора к реальной сети.

Cisco XXX:

GNS ---> What is this ?:   https://habrahabr.ru/     Установка, настройка

https://rutracker.org/forum/viewtopic   <-- Cisco  2960, 2960S, 2960X, 3560X, 3750G, 3750X, 2921, 2951

GNS3, a front-end interface for Dynamips         GNS3 v0.8.2 BETA all-in-one

Dynagen, a front-end interface for Dynamips    Dynagen

https://habrahabr.ru/post/135884/

Введение в структуру операционной системы Cisco IOS

Если бы вас попросили назвать самые известные и широко используемые операционные системы, какие из них вы бы выбрали? Вероятнее всего, в ваш список попали бы такие названия, как UNIX, MS-DOS, Microsoft Windows и даже MVS — операционная система фирмы IBM для мэйнфреймов. Все вышеперечисленные системы известны довольно широко, и одна из них наверняка установлена на вашем компьютере. Но если задуматься на минутку — ведь существуют же и другие! Отметили ли вы в своем списке такую систему, как Cisco IOS? Скорее всего, нет, хотя IOS на сегодняшний день является одной из наиболее развитых операционных систем.

В отличие от операционных систем общего назначения, IOS никогда не используется нами напрямую. Большинство пользователей, работающих с Internet, даже не подозревают, что за всем этим стоит IOS. Впрочем, даже те, кто непосредственно имеют дело с IOS, зачастую воспринимают ее не как полноценную систему, а лишь как программу, управляющую работой маршрутизатора Cisco.

Система IOS не позволяет вам пользоваться текстовым редактором или какими-либо бухгалтерскими приложениями, как это делают другие системы общего назначения. Однако IOS все же, является полноценной операционной системой, пусть и предназначенной лишь для быстрого и эффективного переключения путей следования информационных пакетов. Именно на этом сосредоточенно все внимание системы IOS, как мы увидим в дальнейшем.

Несмотря на то что устройство операционной системы IOS базируется на тех же самых принципах, что и устройство систем общего назначения, компоненты IOS зачастую содержат заметные отличия, обусловленные поставленными перед данной системой задачами. В данной главе мы рассмотрим основополагающие программные элементы операционной системы IOS и посмотрим, насколько разумно она сконструирована.

Для начала мы познакомимся с основными концепциями и определениями, которые будут полезны для дальнейшего понимания устройства системы IOS. Если вы уже знакомы с принципами работы операционных систем, не теряйте времени и переходите к изучению раздела “Структура операционной системы IOS”. Заключительная часть главы посвящена наиболее важным структурным элементам системы IOS.

Устройство операционных систем

Перед cовременными операционными системами стоят две основные задачи: управление ресурсами и логическое разделение между аппаратной и программной частями вычислительной системы. Такое разграничение предоставляет разработчикам интерфейс между прикладными программами и аппаратной частью компьютера. Это означает, что программисту вовсе не обязательно знать тонкости аппаратуры: ведь программный код, общающийся непосредственно с различными устройствами, уже написан и встроен в операционную систему. Программисту остается лишь воспользоваться возможностями системы, а не изобретать велосипед.

Другой функцией операционной системы является управление ресурсами компьютера (например, рабочим временем центрального процессора, памятью или дисковым пространством). Такое централизованное управление дает возможность нескольким приложениям эффективно использовать одни и те же вычислительные ресурсы. Как и в случае с аппаратной частью, программист освобожден от необходимости встраивать в свои приложения какой-либо программный код, занимающийся управлением компьютерными ресурсами.

Управление ресурсами центрального процессора и многозадачность

Некоторые операционные системы позволяют выполнять только одну программу в конкретный промежуток времени (таким образом, например, работает большинство систем семейства MS-DOS). Однако большинство современных операционных систем позволяет приложениям функционировать совместно. Ситуация, когда программы выполняются одновременно, называется многозадачностью (multitasking), а операционная система, позволяющая работать в таком режиме, — многозадачной операционной системой (multitasking operating system).

Компьютерные программы, написанные для многозадачных систем, сами зачастую содержат несколько независимых задач, выполняющихся параллельно. Подобные маленькие программы-задачи получили название потоков (threads), поскольку они все вместе формируют единый поток выполняемых инструкций программы. Каждый поток снабжен персональным набором значений регистров центрального процессора — контекстам (context). Потоки, выполняемые внутри одной программы, могут использовать общую область оперативной памяти. Группа потоков, разделяющих общее пространство памяти и совместно пользующихся ресурсами операционной системы, носит название процесса (process). Если процессор и операционная система поддерживают работу с так называемой виртуальной памятью*, то каждый отдельно взятый процесс может выполняться в своем адресном пространстве, защищенном от доступа со стороны других процессов.

 *** Программе не обязательно знать свое точное месторасположение в памяти и в многозадачных системах используется относительная адресация, а процессы полагают что им выделена вся оперативная память, что в том числе позволяет симулировать наличие в системе большего количества памяти чем есть на самом деле.

Поскольку в конкретный момент времени процессор может отрабатывать инструкции только одной программы, операционная система должна сама решать, какие именно наборы инструкций (потоки) будут выполняться. Процесс принятия решений такого рода называется планированием (scheduling). Планирование задач обычно возлагают на центральную часть операционной системы — ядро (kernel). В зависимости от специфики приложений, на исполнение которых рассчитана конкретная операционная система, могут использоваться различные механизмы планирования потоков. Различные типы приложений (пакетные приложения, интерактивные, программы реального времени) по-разному загружают центральный процессор. Поэтому в целом производительность системы существенно зависит от выбранного механизма планирования.

Простейший метод планирования заключается в выстраивании всех потоков в порядке их появления и выполнении каждого потока до его полного завершения. Этот механизм получил название исполнение до полного завершения в порядке FIFO (first-in-first-out — аналог очереди: первым вошел — первым вышел). Несомненными преимуществами данного метода планирования являются простота реализации, очень низкий показатель вычислительных затрат и его “справедливость” — все потоки обрабатываются поочередно по мере их появления.

Рассмотренный метод планирования хорошо применим для пакетных и некоторых транзакционных приложений, которые последовательно обрабатывают данные, а затем завершают свою работу. В тоже время данная схема абсолютно не применима для интерактивных приложений и приложений реального времени. Поскольку интерактивные программы должны оперативно обслуживать внешние устройства и реагировать на команды пользователя, такие приложения требуют быстрого, хотя и кратковременного доступа к ресурсам центрального процессора. Одним из путей решения данной проблемы является назначение приоритетов для каждого потока. Критичные по времени выполнения потоки, требующие оперативности со стороны центрального процессора, наделяются более высоким приоритетом, нежели, скажем, пакетные приложения. Потоки с более высоким приоритетом могут напрямую перемешаться в начало очереди ожидающих выполнения потоков. Если же в очереди присутствует несколько потоков с одинаковым приоритетом, то они выполняются в порядке их появления (так же, как и для обычного планирования FIFO). Описанный метод планирования носит название приоритетное исполнение до полного завершения (run-to-completion priority scheduling).

Несмотря на то что приоритетное планирование задач имеет несомненные преимущества перед планированием FIFO, оно все же имеет серьезный недостаток — поток с высоким приоритетом может монополизировать использование центрального процессора. К тому же, если процессор уже занят выполнением потока с низким приоритетом, отнимающем больше процессорного времени, потоки с более высоким приоритетом “застревают” в очереди на выполнение, ожидая освобождения процессора. Для решения возникшей проблемы рассмотренный метод планирования должен иметь возможность откладывать (прерывать) выполнение текущего потока, таким образом, чтобы другие потоки могли пользоваться ресурсами центрального процессора.

Приоритетное прерывание выполнения

Вынужденная остановка выполнения одного потока с целью предоставления ресурсов центрального процессора называется приоритетным прерыванием (preemption), а соответствующий метод планирования — планированием с приоритетным прерыванием (preemptive scheduling, или "преемптивное" планирование). Функция преемптивного прерывания всецело возлагается на ядро операционной системы, которое периодически меняет выполняемые процессором потоки путем переключения контекстов (context switch). Сигналом, по которому будет происходить переключение контекстов, может выступать, к примеру, системный таймер или же прямой вызов функции ядра системы. В первом случае каждому потоку выделяется промежуток времени выполнения центральным процессором. По истечении этого времени поток искусственно прерывается, и ресурсы передаются следующему. Если же поток сам решил передать полномочия своим конкурентам, он вызывает специальную функцию ядра системы, которая и осуществляет переключение потоков. Итак, когда поступает сигнал на переключение контекстов, ядро выбирает очередной поток из очереди, а прерванный поток возвращает назад ожидать следующей возможности использовать ресурсы процессора.

Внимание!

Как мы уже видели, переключение контекстов буквально означает, что ядро системы освобождает центральный процессор от выполнения одного потока и назначает выполнение следующего. Другими словами, компьютер просто меняет задачу, над которой он работает. Однако само переключение контекстов тоже является задачей, отнимающей процессорное время. Ведь все значения регистров (контекст) прерванного потока должны быть сохранены, а регистры очередного потока соответственно загружены. Контекст позволяет задаче, получающей право на выполнение, “вспомнить" то, чем она занималась во время последнего ее прерывания.

Перечислим основные преимущества многозадачности с приоритетным прерыванием:

Конечно, рассмотренный метод планирования имеет и свои недостатки, которые перечислены ниже.

Управление памятью

Операционная система также осуществляет управление оперативной памятью компьютера. Обычно память разделяется на различные части: одна часть используется для размещения кода (инструкций, выполняемых центральным процессором), другая — для программных данных. Свободная область памяти, из которой система может динамически выделять области для последующего использования, получила название кучи (heap).

Некоторые операционные системы позволяют процессам адресовать большее пространство памяти, нежели физически установлено в компьютере, — это так называемая виртуальная память (virtual memory). Механизм виртуальной памяти позволяет расширить область доступной памяти за счет использования дополнительного носителя, такого как жесткий диск. Использование виртуальной памяти базируется на аппаратной особенности некоторых процессоров, внутри которых содержится так называемый блок управления памятью (memory management unit — MMU). Механизм MMU автоматически переадресует запросы или к оперативной памяти (random access memory — RAM), или к дополнительному носителю (жесткий диск), в зависимости от того, где в действительности находятся запрашиваемые данные. Использование механизма MMU также позволяет защищать фрагменты памяти, помечая их атрибутом “только для чтения” или вообще исключая из операций с картой памяти*.

Виртуальная память обладает также и другими преимуществами: механизм MMU может быть запрограммирован таким образом, чтобы отделять области памяти различных процессов друг от друга. Таким образом, предотвращается доступ к памяти одного процесса со стороны других.

Наделенная всеми своими достоинствами, виртуальная память не дается системе “даром”. Платить приходится производительностью. Именно по этой причине система IOS не использует механизм виртуальной памяти в полной мере, как мы увидим в дальнейшем.

***Потеря данных во время прерывания выполнения, целиком возложены на операционную систему, используя механизмы виртуальной памяти и страничной адресации, система полностью исключает возможность "порчи" данных одного процесса другим.

***Фрагменты памяти, используемые наиболее часто, обычно помещаются в оперативной памяти. Редко используемые данные при этом выгружаются на диск. Если приложение обращается к участку памяти, который в данный момент выгружен на диск, система считывает его в оперативную память и лишь после этого предоставляет приложению доступ к данным. Для некоторых участков памяти можно запретить проводить такие операции. В этом случае система не будет перемещать указанный фрагмент или выгружать его на диск.

Прерывания

Операционные системы обычно осуществляют обработку прерываний центрального процессора. Прерывание — это аппаратное событие, по которому выполнение текущего набора инструкций приостанавливается, а управление передается специальной программе. Эта специальная программа — обработчик прерывания (interrupt handler) — выполняет необходимые действия, связанные с природой прерывания, и возвращает процессор к выполнению приостановленного набора инструкций. Зачастую прерывания генерируются внешними устройствами-контроллерами, требующими внимания со стороны системы. Однако и сам центральный процессор может генерировать прерывания. Операционная система, поддерживающая обработку прерываний, содержит различного рода обработчики для всех видов возможных прерываний.

Структура операционной системы IOS

Изначально IOS проектировалась как маленькая операционная система, встраиваемая в первые маршрутизаторы Cisco. В те времена маршрутизаторы сами по себе рассматривались как устройства исключительно аппаратные. Разделения между программной и аппаратной частями практически не происходило. Поначалу операционную систему IOS даже не называли IOS, а лишь системой, управляющей маршрутизатором Cisco.

С ростом популярности маршрутизируемых сетей возникла потребность в маршрутизаторах, которые бы поддерживали различные протоколы и обеспечивали дополнительную функциональность, такую, например, как коммутация. В ответ на повышение требований к маршрутизаторам Cisco вносила различные дополнения в программное обеспечение. В результате IOS превратилась в многофункциональную операционную систему, поддерживающую маршрутизацию и коммутацию. Интересно отметить, что, несмотря на значительное расширение функциональных возможностей системы, основные концепции структуры системы IOS остались практически неизмененными.

По сравнению с другими операционными системами, структура системы IOS очень проста. Как и большинство маленьких встраиваемых операционных систем, IOS была спроектирована таким образом, чтобы занимать как можно меньшее пространство памяти и функционировать максимально быстро. Первоначально маршрутизаторы были оснащены небольшим объемом памяти для хранения программного обеспечения и данных (таких как таблицы маршрутизации). Чтобы достигнуть очень маленьких размеров выполняемого образа операционной системы, IOS была оснащена лишь самыми необходимыми функциями.

Необходимая производительность операционной системы также сыграла решающую роль в проектировке структуры IOS. Значительные усилия были потрачены на создание системы, позволяющей маршрутизатору перенаправлять сетевые пакеты с максимальной скоростью. Это потребовало уменьшения расходов процессорного времени на служебные нужды операционной системы, что позволило максимально эффективно использовать ресурсы процессора для маршрутизации сетевых пакетов. Различные меры защиты, такие как механизм защиты внутрипотоковой памяти, присутствующие в других операционных системах, исключены из системы IOS с целью снижения затрат процессорных ресурсов на обслуживание нужд системы. 

В целом идея IOS состоит в том, чтобы достичь максимальной скорости работы, пусть и ценой снижения эффективности защиты системы от сбоев.

 Основные элементы системы, перечислены ниже:

Все описанные элементы операционной системы IOS мы рассмотрим в последующих разделах. Программное обеспечение механизма быстрого переключения пакетов будет рассмотрено в главе 2, “Принципы коммутации пакетов”. Прежде чем мы займемся детальным обсуждением вышеуказанных архитектурных компонентов, рассмотрим, как организована память системы IOS.

   Организация памяти

Операционная система IOS проецирует всю имеющуюся физическую память в одну непрерывную область виртуального адресного пространства. Как мы уже отмечали выше, в системе IOS не реализован полноценный механизм виртуальной памяти. Для снижения вычислительных затрат на обслуживание системы и процессов ядро IOS не поддерживает ни страничную адресацию памяти, ни подкачку отдельных областей памяти. Таким образом, все адресное пространство системы IOS ограничено объемом доступной физической памяти.

Всю память операционная система IOS разделяет на отдельные области (regions), которые обычно соответствуют различным типам физической памяти. Например, 

Разделение памяти по областям позволяет системе IOS объединять различные типы памяти, а программы даже не знают особенностей памяти на конкретной аппаратной платформе.

Все области памяти классифицируются по одной из восьми категорий, которые перечислены в таблице справа.


Разновидности областей памяти

Области памяти могут быть вложенными в отношении “родительская область— дочерняя область”. 

В принципе, ограничений на глубину подобного рода вложений нет, однако реально используется лишь один уровень. Вложенные области формируют подобласти (subregions) родительских областей. На рис. 1.2 проиллюстрирована возможная в системе IOS конфигурация памяти с областями и под областями. Для того чтобы узнать, какие области памяти присутствуют в данной системе, используется команда show region

В примере 1.1 продемонстрирован результат выполнения этой команды для маршрутизатора Cisco 7206.

Пример 1.1. Результат выполнения команды show region

router#show region

Region Manager:

Start          End         Size(b)    Class      Media     Name

0x1A000000     0x01FFFFFF  6291456    Iomem      R/W       iomem

0X31A00000     0x31FFFFFF  6291456    Iomem      R/W       iomem:(iomem cwt)

0х4В000000     0x4B0FFFFF  1048576    PCI        R/W       pcimem

0x60000000     0x619FFFFF  27262976   Local      R/W       main

0x600088F8     0x61073609  17214738   IText      R/O       main:text

0x61074000     0x611000FF  573696     IData      R/W       main:data

0x61100100     0x6128153F  1578048    IBss       R/W       main:bss

0x61281540     0x619FFFFF  7858880    Local      R/W       main:heap

0x7B000000     0x7B0FFFFF  1048576    PCI        R/W       pcimem:(pcimem cwt)

0x80000000     0x819FFFFF  27262976   Local      R/W       main:(main k0)

0xA0000000     0xA19FFFFF  27262976   Local      R/W       main:(main k1)


Cisco-7200VXR_NPE-175#show region

Region Manager:

Start        End          Size(b)     Class    Media  Name

 0x0F000000  0x0FFFFFFF   16777216    Iomem    R/W    iomem

 0x60000000  0x6EFFFFFF   251658240   Local    R/W    main

 0x60008AF4  0x61A5AEB7   27599812    IText    R/O    main:text

 0x61A5C000  0x628EE8BF   15280320    IData    R/W    main:data

 0x628EE8C0  0x62D460BF   4552704     IBss     R/W    main:bss

 0x62D460C0  0x6EFFFFFF   204185408   Local    R/W    main:heap

 0x7F000000  0x7FFFFFFB   16777212    Iomem    R/W    iomem:(iomem_cwt)

 0x80000000  0x8EFFFFFF   251658240   Local    R/W    main:(main_k0)

 0xA0000000  0xAEFFFFFF   251658240   Local    R/W    main:(main_k1)

Колонки Start и End выведенной таблицы указывают на начальные и конечные адреса областей памяти в общем пространстве виртуальной памяти системы. Справа указаны соответствующие области и подобласти. Имена подобластей не выделены скобками и отделены двоеточием от соответствующих имен областей. На рис. 1.3 изображены соответствующие области памяти с подобластями.

Между различными областями памяти преднамеренно оставлены пропуски в пространстве адресов (например, область pcimem оканчивается на адресе 0x4B0FFFFF, а область main начинается с адреса 0x60000000). Эти свободные области могут использоваться для расширения и предоставляют некоторого рода защиту от выполнения потоков с ошибками. Если вышедший из под контроля поток начнет записывать мусор в различные участки памяти, то такой поток немедленно будет остановлен при попытке записать что-либо в свободную область.

Из примера 1.1 и рис. 1.3 мы видим, что вся область DRAM-памяти, начиная с адреса 0x60000000 и заканчивая адресом 0x619FFFFF, рассматривается как локальная область (local) и разделяется на несколько подобластей. Такие подобласти соответствуют различным частям образа системы IOS (текст, BSS и данные), а также куче. Кучей обозначается вся свободная локальная память после того, как в нее был загружен образ системы.

Названия некоторых областей повторяются в различных адресах памяти, как, например, для области iomem:(iomem_cwt):

Start        End           Size(b)    Class     Media   Name

0x01A00000   0x01FFFFFF    6291456    Iomem     R/W     iomem

0x31А00000   0x31FFFFFF    6291456    Iomem     R/W     iomem:(iomem cwt)

Такие повторяющиеся регионы называются алиасами {aliases). В некоторых платформах Cisco используется несколько диапазонов адресов для указания одной и той же области памяти. Алиасы используются для обеспечения альтернативного метода доступа к данным в памяти. Например, один диапазон адресов может использоваться для кэшированного доступа к региону памяти, в то время как другой диапазон адресов обеспечивает некэшируемый доступ к тому же самому участку памяти. Дублируюшие области памяти создаются в процессе инициализации системы. Естественно, алиасы не учитываются при вычислении обшего объема памяти системы (потому что они на самом деле не являются отдельной физической памятью, а лишь предоставляют альтернативный метод доступа).


Пулы памяти

Управление памятью в системе IOS осуществляется посредством так называемых пулов памяти memory pools - каждый пул представляет собой блок памяти, который может быть выделен из кучи или освобожден от использования. 

Пулы составляются из областей памяти, а управление ими осуществляется ядром системы. Очень часто пул памяти в точности соответствует области памяти, однако один пул может покрывать и несколько участков памяти. Таким образом, память может выделяться для использования сразу из нескольких областей, что оказывается весьма эффективным.

Информация о пулах памяти может быть получена с помощью команды show memory.

Пример 1.2. Результат выполнения команды show memory

router#show memory

            Head        Total(b)   Used(b)      Free(b)     Lowest(b)     Largest(b)

Processor   61281540    7858880    3314128      4544752     4377808       4485428

I/O         1А00000     6291456    1326936      4964520     4951276       4964476

PCI         4B000000    1048576    407320       641256      641256        641212







Из примера 1.2 видно, что в системе выделены три пула памяти: Processor, I/O и PCI

Сравнивая значения колонки Head (адрес пула) с соответствующими значениями из колонки Start (начальный адрес) команды show region, можно определить, какие области покрывает каждый пул памяти.

Внимание!

На самом деле команда show memory выводит очень много различной информации. Поэтому не следует использовать эту команду при отключенном страничном выводе информации на консоль (размер буфера терминала установлен в значение, равное 0), поскольку невозможно остановить вывод до полного его завершения.

Пример 1.3. Информация, выводимая командой Show region 

router#show region

Region Manager:

Start         End             Size(b)     Class     Media    Name

0x01A00000    0x01FFFFFF      6291456     Iomem     R/W      iomem

0x31A00000    0x31FFFFFF      6291456     Iomem     R/W      iomem:(iomem cwt)

0x4B000000    0X4B0FFFFF      1048576     PCI       R/W      pcimem

0x60000000    0x619FFFFF      27262976    Local     R/W      main

0x600088F8    0x61073609      17214738    Itext     R/O      main:text

0x61074000    0x611000FF      573696      Idata     R/W      main:data

0x61100100    0x6128153F      1578048     Ibss      R/W      main:bss

0X61281540    0x619FFFFF      7858880     Local     R/W      main:heap

.....................................



Из примера 1.3 видно, что пул памяти процессора (Processor memory pool) включает подобласть под названием куча (heap) из основной области (main region), который, в свою очередь, принадлежит к локальному классу (class Local). Пул памяти процессора присутствует во всех IOS-системах и всегда размещается в локальной памяти. Для размещения различных данных (таких как таблицы маршрутизации) из процессорного пула памяти выделяется необходимая часть. Аналогичным образом пул ввода-вывода (I/O pool) отвечает за память региона iomem, а пул шины PCI — соответственно за регион pcimem.

В выводе команды show memory присутствует еще несколько колонок, которые отображают различную информацию о пулах. Ниже приведено краткое описание этих значений (все показатели измеряются в байтах).

Как мы увидим далее, команда show memory может отображать выделенные блоки памяти внутри каждого пула.

Процессы в системе IOS

Процессы операционной системы IOS эквивалентны потокам в других операционных системах, поскольку в IOS процессы состоят лишь из одного потока. Каждый процесс наделен собственным стеком, контекстом центрального процессора и может распоряжаться ресурсами памяти и консольными устройствами, о которых мы поговорим позднее. Чтобы снизить затраты на обслуживание, система IOS не реализует механизм зашиты областей памяти отдельных процессов. Также не осуществляется управление памятью во время переключения контекстов. Все это означает, что хотя каждому процессу и выделена своя область памяти, ничто не мешает ему вторгаться в память другого процесса.

Как мы уже отмечали раньше, операционная система IOS использует модель приоритетного выполнения до полного завершения для планирования своих процессов. Может показаться, что использование планирования без приоритетных прерываний — не лучшее решение для системы, которая должна оперативно обслуживать входящие сетевые пакеты. В некоторых случаях так оно и есть: потребность в оперативности выходит за ограничения механизма планирования процессов в системе IOS. 

В главе, “Принципы коммутации пакетов”, мы расскажем, как была решена рассмотренная проблема. Все же механизм планирования задач операционной системы IOS имеет массу несомненных преимуществ, что позволяет использовать его для обслуживания процессов, не претендующих на сверх-оперативность переключения пакетов. Перечислим некоторые положительные стороны данного подхода.

 ***Если два процесса выполняются параллельно и пытаются изменить один и тот же ресурс (например, переменную памяти), то результат оказывается непредсказуемым. Для обеспечения однозначности процесс можно прервать лишь в момент, когда он не использует этот общий ресурс. Операционные системы с приоритетным прерыванием следят за этим сами, используя так называемые семафоры. В IOS же за возможный момент переключения процессов ответствен программист.

Цикл жизни процесса

Процессы могут “рождаться и умирать” в любой момент работы системы IOS, исключая время обработки прерывания. Процесс может создаваться или “уничтожаться” ядром системы (во время инициализации IOS) или любым другим выполняющимся процессом.

 Внимание!

Говоря о прерываниях, мы будем иметь в виду аппаратные прерывания. Когда процессору поступает сигнал прерывания, выполнение текущего потока откладывается и процессор переходит к выполнению функции обработки прерывания. Соответственно новые процессы не могут создаваться, если процессор занят отработкой прерывания.

    В частности, за возникновением большинства процессов операционной системы IOS ответствен процесс синтаксического анализатора (parser). Синтаксический анализатор представляет собой набор функций, которые интерпретируют конфигурационные файлы системы IOS и исполняемые команды (ЕХЕС). 

    Синтаксический анализатор вызывается ядром системы во время инициализации и процессом ЕХЕС, который предоставляет интерфейс командной строки - CLI для консоли или сессии Telnet. Будь то команда, введенная пользователем, или строка, прочитанная из конфигурационного файла, синтаксический анализатор обрабатывает поступившие данные и предпринимает соответствующие действия. 

    Команды конфигурации могут отвечать за установку различных значений (как, например, IP-адресов), а также параметров маршрутизации и за мониторинг событий. Некоторые команды требуют, чтобы синтаксический анализатор породил новый процесс. 

К примеру, получив через интерфейс командной строки конфигурационную команду router eigrp, анализатор создает новый процесс, именуемый ipigrp (если, конечно, такой процесс еще не запущен в системе), который занимается обслуживанием IP-пакетов протокола EIGRP.  Если же введена команда no router eigrp, анализатор прекращает работу процесса ipigrp и соответственно пакеты IP EIGRP больше не обрабатываются маршрутизатором. Жизнь процессов в системе IOS состоит из нескольких фаз, ниже изображены эти фазы и соответствующие им состояния процессов.

Фаза рождения

Когда новый процесс рождается, он получает в распоряжение собственный стек и переходит в состояние “новый” (new). После этого процесс может перейти в фазу трансформации. Если же нужды в трансформации нет, то процесс напрямую следует в фазу своего выполнения.

Фаза трансформации

По умолчанию операционная система IOS не передает новому процессу никаких начальных параметров и не назначает консоль (как это делает большинство операционных систем), поскольку большинству процессов они просто не нужны. Если процессу все же требуются такие ресурсы, то поток, породивший его, может его трансформировать, выделяя соответствующие ресурсы.

Фаза выполнения

После того как новый процесс был успешно создан и подвергся трансформации, он переходит в состояние готовности (ready), находясь уже в фазе выполнения (execution). В этой фазе процесс получает доступ к центральному процессору и, собственно, совершает некую полезную работу. Находясь в фазе выполнения, процесс может принимать одно из трех состояний: готовность, выполнение или простой. 

Процесс в состоянии готовности ожидает своей очереди на пользование ресурсами процессора. Выполняющийся процесс уже получил доступ к центральному процессору, который и занимается выполнением инструкций этого процесса. Процесс, находящийся в состоянии простоя, “спит”, ожидая какого-то события извне. Если такое событие происходит, процесс может выполняться.

Переход процесса из состояния готовности в состояние выполнения контролируется планировщиком. Поскольку многозадачность операционной системы IOS не использует приоритетное прерывание, то, получив право на выполнение, процесс занимает центральный процессор, выполняясь до полного своего завершения либо периодически приостанавливая свою работу. Приостановить свое выполнение процесс может двумя способами. 

Процесс может напрямую сообщить ядру, что он желает освободить центральный процессор от использования, и тогда ядро системы приостанавливает выполнение процесса и переводит его в состояние готовности, где он вновь ожидает своей очереди на выполнение. 

Также процесс может остановить свою работу, ожидая какого-то внешнего события. В таком случае он переходит в состояние простоя и остается в нем, пока не наступит желаемое событие. Как только это событие наступает, ядро переводит ожидающий процесс в состояние готовности, и он ожидает своей очереди на выполнение.

Фаза уничтожения

Последняя фаза в жизненном цикле процесса — фаза уничтожения. Процесс входит в эту фазу после завершения всех своих задач и прекращает работу (так называемое самостоятельное завершение работы). Процесс также может быть “убит” и другим процессом. Когда процесс завершил работу самостоятельно или под действием другого процесса, он переходит в состояние “мертвый” (dead). Завершившиеся процессы пребывают в “мертвом” состоянии, пока ядро не освободит все занимаемые ими ресурсы. Ядро может также сохранить информацию об использовании процессом стека. После того как все ресурсы “мертвого” процесса освобождены, он полностью выгружается из системы.

Приоритеты процессов в системе IOS

Планируя выполнение своих процессов, операционная система IOS использует политику приоритетов. При рождении процесса ему назначается один из четырех приоритетов, в зависимости от целей данного процесса. Впоследствии приоритет процесса не изменяется. Приведем описание возможных приоритетов процессов операционной системы IOS.

В зависимости от приоритетов механизм приоритетов дает различным процессам различные привилегии на доступ к процессорным ресурсам. Однако следует помнить, что операционная система IOS не реализует приоритетные прерывания. Таким образом, процесс с более высоким приоритетом не может прервать выполнение процесса с более низким приоритетом. Вместо этого система IOS предоставляет процессам с высоким приоритетом больше возможности захватить процессорные ресурсы.

Примеры процессов

    Для того чтобы определить, какие процессы выполняются в системе, используется команда show process. Результат исполнения команды включает также дополнительную информацию о каждом процессе (пример 1.4).

Пример 1.4. Результат работы команды show process.

Cisco-7200VXR_NPE-175 # show process

PID     QTy    PC Runtime (ms)  Invoked   uSecs Stacks   TTY  Process

   1    Cwe    607BF5B8   0     1         0 5604/6000    0    Chunk Manager  

   2    Csp    607EE634   0     40        0 2632/3000    0    Load Meter 

   3    Lwe    605F1364   0     7         0 5444/6000    0    CEF Scanner

   4    Mwe    612C3D50   0     1         023464/24000   0    EDDRI_MAIN

   5    Lst    607CE018   156   22        7090 5632/6000 0    Check heaps

   6    Cwe    607D417C   0     1         0 5592/6000    0    Pool Manager

   7    Mst    60704B28   0     2         0 5584/6000    0    Timers

   8    Mwe    60011A28   4     2         2000 5584/6000 0    Serial Backgroun

   9    Mwe    6023D330   0     2         0 5584/6000    0    ATM Idle Timer

  10    Mwe    602C21E8   0     2         0 8580/9000    0    ATM AutoVC Perio

  11    Mwe    602C1C4C   0     2         0 5584/6000    0    ATM VC Auto Crea

  12    Mwe    606D767C   0     2         0 5576/6000    0    AAA high-capacit

  13    Msi    6088A438   20    192       104 5628/6000  0    EnvMon

  14    Mwe    6088FE1C   0     1         0 8608/9000    0    OIR Handler

  15    Mwe    608A6228   0     4         0 5680/6000    0    IPC Dynamic Cach

  16    Mwe    6089E630   0     1         0 5636/6000    0    IPC Zone Manager

  17    Mwe    6089E390   0     193       0 5708/6000    0    IPC Periodic Tim

  18    Mwe    6089E2D8   0     193       0 5624/6000    0    IPC Deferred Por

  19    Mwe    6089E444   0     1         0 5596/6000    0    IPC Seat Manager

  20    Mwe    608FBFB8   4     6         666 5588/6000  0    ARP Input

  21    Mwe    60B7A0CC   0     10        0 5664/6000    0    HC Counter Timer

 --More--

Ниже описаны значения полей вывода команды show process.

PID — идентификатор процесса (process identifier). Каждому процессу назначается уникальный идентификатор, который позволяет различать процессы в системе.

Qty — приоритет процесса и его состояние. Первый символ данного поля показывает приоритет процесса:

    К  — приоритет не назначен, так как процесс был “убит”;

    D  — нет приоритета, так как процесс разрушен;

    X  — нет приоритета, так как процесс поврежден;

    С   — критический приоритет;

    Н  — высокий приоритет;

    М  — средний приоритет;

    L   — низкий приоритет.

Два последующих символа обозначают текущее состояние процесса.

    *   — в данный момент процесс выполняется ЦП.

    Е  — процесс ожидает события.

    S   — процесс приостановлен.

    rd — процесс готов к выполнению.

    we — процесс простаивает в ожидании события.

    sa  — процесс простаивает, ожидая некоего абсолютного времени.

    si   — процесс простаивает, ожидая истечения  интервала времени.

    sp  — процесс простаивает, ожидая истечения временного интервала (периодически).

    st   — процесс простаивает, ожидая истечения временного интервала таймера.

    hg  — процесс “подвешен”.

    хх   — “мертвый” процесс.


Если выполнить команду show process на различных системах IOS, можно заметить, что некоторые процессы присутствуют в каждой системе. Большинство из этих процессов выполняют сервисные функции или обслуживают другие процессы. В табл. 1.2 приведен список таких процессов с описанием выполняемых ими задач.

 Общесистемные процессы и их функции

Все описанные выше процессы (за исключением ЕХЕС) создаются ядром системы во время инициализации и обычно существуют в операционной системе IOS вплоть до ее остановки.

Ядро системы IOS

    В терминах операционной системы ядро представляет собой “сердцевину” системы, ее центральную часть, выполняющуюся в специальном защищенном режиме процессора и управляющую системными ресурсами. Несмотря на то что ядро помогает управляться с ресурсами системы, структура его отличается от ядер других операционных систем. 

    Ядро операционной системы IOS не является отдельным модулем, а представляется довольно широким набором компонентов и функций, связанных с остальными частями системы, и выступает наравне с ними, а не как управляющий элемент. 

    Для ядра не существует “специального” режима выполнения. Все процессы, не исключая и ядра, выполняются на процессорном уровне пользователя и имеют полный доступ к системным ресурсам.

    Ядро операционной системы IOS планирует выполнение процессов, управляет памятью, предоставляет сервисные функции для захвата и обработки аппаратных прерываний, поддерживает таймеры и обрабатывает программные исключения.

Планировщик

    Все задачи, касающиеся планирования процессов, целиком и полностью возлагаются на планировщик (scheduler). Планировщик системы IOS координирует работу всех процессов в системе с помощью так называемых очередей процессов (process queue), каждая из которых соответствует определенному состоянию процесса. Очереди также хранят информацию о контекстах процессов в соответствующих состояниях. Процессы переходят из одного состояния в другое, тогда как планировщик перемещает их контексты из одной очереди в другую. Итак, существует шесть очередей процессов, которые перечислены ниже.

    Когда выполняющийся процесс приостанавливается, управление ресурсами процессора берет на себя планировщик. Используя специальный алгоритм, планировщик выбирает из очередей готовых процессов один и предоставляет ему ресурсы процессора. Рассмотрим последовательность действий планировщика поэтапно.

 Алгоритм работы планировщика в чем-то схож с работой секундомера или алгоритмо "часы". В данной аналогии 

секунды —как критичные процессы, 

минуты — как процессы с высоким приоритетом, 

часы — как процессы со средним приоритетом и 

дни — как низкоприоритетные процессы. 


Каждый оборот секундной стрелки покрывает все секунды. Каждый оборот минутной стрелки покрывает все минуты, включая и прошествие всех секунд для каждой минуты, и т.д.

Так же как и секундомер, алгоритм планировки имеет встроенную функцию сброса. Планировщик не переходит к обработке очереди процессов со средним приоритетом, цока есть высокоприоритетные процессы, ожидающие выполнения.   Когда планировщик обнаруживает в очереди высокоприоритетные процессы, он начинает выполнение алгоритма планировки с самого начала, обрабатывая критичные процессы, а затем высокоприоритетные (как и секундомер сбрасывает значение в нуль по прошествии часа).

Использование ресурсов центрального процессора

    Хотя система IOS и не предоставляет никаких статистических данных о работе планировщика, существует способ узнать, как различные процессы разделяют ресурсы центрального процессора. В предыдущих примерах мы рассматривали результат работы команды show process, которая выводит общую информацию об активных процессах в системе. 

    Модификация данной команды  show process epu  имеет довольно схожий результат работы, однако внимание ее больше сосредоточено на использовании ресурсов центрального процессора. Результат работы команды show process epu приведен в примере 1.5.

Первая строка в выводе команды show process cpu показывает общую загрузку центрального процессора, усредненную по трем различным интервалам времени: 5 секунд, 1 минута и 5 минут. Пятисекундная статистика использования процессора представлена двумя числами, разделенными косой чертой. 

Число слева представляет общий процент использования ресурсов процессора (процентзанятости).     

Число справа — процент использования ресурсов процессора при обработке прерываний. 

Одно и пятиминутная статистика использования процессорного времени показывает общий процент занятости процессора, значение которого экспоненциально уменьшается для одно- и пятиминутной статистики соответственно.

    После обшей статистики использования процессора те же самые временные интервалы отображают загруженность каждого процесса в отдельности. Планировщик автоматически просчитывает данные значения и сохраняет их в памяти на случай выполнения команды show process epu. Таким образом, выполняя команду show process epu дважды в течение пятисекундного интервала, мы не увидим обновленной статистики использования центрального процессора.

    С помощью команды show process epu довольно просто определить наиболее активные в системе процессы и процент использования ими ресурсов центрального процессора. В приведенном выше примере средняя загруженность процессора в течение пяти секунд перед запуском команды составляла 90%. 

Средняя загруженность при обработке прерываний — 82%. 

Оставшиеся 8% (90% — 82% = 8%) используются планировщиком. 

    В течение последних 60 секунд загруженность процессора составила 60%, а средняя загруженность в течение пяти минут — 40%. Из индивидуальной для каждого процесса информации видно, что в течение последних пяти секунд 8?% процессорных ресурсов было занято процессом ip_input. Нулевые значения показателей загруженности означают, что процесс не имел возможности выполняться в промежутке соответствующего интервала либо значение загруженности составляло меньше 0,01%.

    Из приведенного выше примера видно, что довольно-таки большой процент процессорных ресурсов приходится на обработку прерываний. Возникает вопрос: чем же занимается операционная система IOS в течение 82% своего рабочего времени? К сожалению, система не предоставляет детальной информации об обработке процессором прерываний, как это сделано для процессов; посему трудно привязать загруженность процессора к конкретной задаче. Однако можно сделать предположение относительно использования процессорных ресурсов. 

    Как вы узнаете в главе , “Принципы коммутации пакетов”, при использовании механизма быстрой коммутации (fast switching) пакетов львиная доля работы выполняется именно на уровне обработки прерываний. Операционная система IOS также выполняет и другую работу, обрабатывая прерывания, однако большая часть времени все же тратится на коммутацию пакетов. Посему высокое значение загруженности процессора обычно означает, что системе IOS приходится заниматься коммутацией большого количества сетевых пакетов.

    Незадействованное процессорное время (10% в нашем примере) носит название времени холостого хода или простоя. “Время простоя”, однако, не совсем точное определение, поскольку процессор на самом деле никогда не простаивает: в нем постоянно выполняются какие-то инструкции (машинные команды). В системе IOS время простоя в действительности означает, что ресурсы процессора используются собственно планировщиком (а это весьма важный процесс в системе). Очень важно, чтобы у операционной системы IOS было достаточно времени холостого хода. При приближении загруженности процессора к 100% на нужды планировщика практически не остается ресурсов, что приводит к весьма серьезным последствиям. Поскольку планировщик отвечает за выполнение всех фоновых критичных процессов, нехватка процессорных ресурсов может привести к отказу системы.

    Cистема IOS располагает так называемым сторожевым таймером, который предотвращает тотальную загруженность центрального процессора. К сожалению, операционная система IOS не всегда применяет этот механизм защиты для прерываний. Хотя многие платформы и поддерживают ограничение на использование ресурсов центрального процессора через так называемые заглушки прерываний, по умолчанию данная функция отключена.

    В любом случае сторожевые таймеры и заглушки прерываний — это всего лишь механизмы безопасности. Когда система планируется для высокоскоростной обработки пакетов (например, если в систему встроено большое количество сетевых интерфейсов, подключенных к загруженным каналам), рациональнее выбрать более производительный процессор и настроить систему на использование наиболее эффективного механизма коммутации для избежания перегрузки центрального процессора.

Сторожевой таймер

    Для уменьшения риска перегруженности процессора операционная система IOS устанавливает сторожевой таймер для процессов, который позволяет планировщику периодически ограничивать выполнение текущего процесса. Не следует пугать этот механизм с преемптивной многозадачностью, поскольку он является всего лишь средством защиты системы от перегруженности и полной блокировки при тотальном занятии процессом процессорных ресурсов. Если процесс в системе окажется подвешенным (например, выполняющимся неоправданно долго), планировщик может остановить его выполнение.

    Каждый раз, когда планировщик предоставляет процессу возможность выполняться, запускается сторожевой таймер для этого процесса. По истечении заданного промежутка времени (по умолчанию 2 секунды), если процесс все еще выполняется, то управление передается обратно планировщику. После первого срабатывания сторожевого таймера планировщик выводит предупреждающее сообщение и продолжает выполнение процесса: 

%SNMP-3-CPUHOG: Processing GetNext of ifEntry.17.6

ISYS-3-CPUHOG: Task ran for 2004 msec (49/46), Process = IP SNMP, PC = 6018EC2C

-Traceback= 6018EC34 60288548 6017E9C8 6017E9B4

Если сторожевой таймер срабатывает во второй раз, а процесс все еще не приостанавливается, планировщик  останавливает выполнение процесса.

Менеджер памяти

    Менеджер памяти ядра несет ответственность на макроуровне за управление всей доступной памятью операционной системы IOS, включая и память, содержащую собственно выполняемый код системы IOS. Менеджер памяти в действительности не единичный компонент и состоит из трех отдельных модулей, каждый из которых отвечает за свои задачи, которые перечислены ниже.

Менеджер областей памяти

    Менеджер областей памяти отвечает за поддержание всех существующих областей. Он предоставляет услуги другим частям операционной системы IOS создавать отдельные области и устанавливать их атрибуты. Менеджер областей также позволяет организовывать запросы для получения информации о доступных областях (например, для определения общего объема доступной памяти).

Менеджер пулов памяти

    Менеджер пулов памяти является весьма важным компонентом системы. Так же как планировщик отвечает за предоставление процессам ресурсов центрального процессора, менеджер пулов памяти предоставляет процессам возможность выделения памяти. Для выделения памяти под собственные нужды процесс должен напрямую или косвенно обратиться к менеджеру пулов памяти. Менеджер пулов отрабатывается каждый раз, когда процесс вызывает стандартные системные вызовы malloc или free для выделения и освобождения памяти соответственно.

    Вся работа менеджера пулов памяти опирается на использование списка свободных блоков памяти внутри каждого пула. Очевидно, что изначально каждый пул содержит по одному большому блоку свободной памяти, размер которого равен размеру пула. В процессе обработки запросов к памяти начальный свободный блок памяти становится все меньше и меньше. В то же время процессы могут освобождать занятые блоки памяти. Таким образом, в ходе работы системы образуется несколько блоков свободной памяти, отличающихся по своим размерам (рис. 1.5). Данное явление носит название фрагментация памяти (memory fragmentation).

    После того как освобожденный блок памяти будет возвращен в пул, менеджер добавляет размер и начальный адрес данного блока в один из списков сходных по размерам свободных блоков. По умолчанию менеджер пулов поддерживает списки для следующих размеров блоков: 

24, 84, 144, 204, 264, 324, 384, 444, 1500, 2000, 3000, 

5000, 10000, 20000, 32768, 65536, 131072 и 262144 байт. 

Следует отметить, что данные размеры никоим образом не связаны с системными буферами, о которых речь пойдет ниже.

    Когда процесс требует выделения памяти, менеджер пулов сначала просматривает список свободных блоков необходимого размера. Этот механизм позволяет более эффективно использовать свободную память за счет близких по размеру блоков памяти. Если в списке блоков подходящего размера не найдено свободных блоков, менеджер переходит к рассмотрению списка блоков большего размера, до тех пор, пока подходящий блок не будет найден. Если менеджеру приходится использовать блок большего размера, чем было запрошено, найденный блок расщепляется и свободная его часть помещается в соответствующий список свободных блоков меньшего размера.

    Менеджер пулов памяти пытается контролировать фрагментацию памяти путем объединения рядом расположенных свободных блоков. Когда блок памяти освобождается, менеджер просматривает память на предмет наличия за освобожденным блоком свободной области. Если такая область найдена, то блоки объединяются в один с последующим размещением его в соответствующий список свободных блоков памяти (рис. 1.6).

    Выше мы рассматривали результат работы команды show memory, выводящей имена и различную информацию о пулах памяти, а также детальную информацию о каждом блоке памяти внутри пулов. Вывод команды show memory содержит список всех блоков памяти, включенных в соответствующие пулы (пример 1.6.)

Cisco-7200VXR_NPE-175 #show memory

              Head       Total(b)     Used(b)    Free(b)      Lowest(b)    Largest(b)

  Processor   62D460C0   204185408    7765220    196420188    196355428    196352972

       I/O    F000000    16777216     1860792    14916424     14916424     14916380

          Processor memory

 Address      Bytes     Prev     Next Ref     PrevF    NextF Alloc PC  what

62D460C0 000002000...... 62D4AF0C 001  -------- -------- 607BC3AC  Managed Chunk Queue Elements

62D4AF0C 0000010000 62D460C0 62D4D648 001  -------- -------- 607CFF5C  List Elements

62D4D648 0000005000 62D4AF0C 62D4E9FC 001  -------- -------- 607CFFA0  List Headers

62D4E9FC 0000000044 62D4D648 62D4EA54 001  -------- -------- 61A520D0  *Init*

62D4EA54 0000000024 62D4E9FC 62D4EA98 001  -------- -------- 608848A4  *Init*

62D4EA98 0000000044 62D4EA54 62D4EAF0 001  -------- -------- 61A520D0  *Init*

63038540 0000000052 63038474 630385A0 001  -------- -------- 607287BC  Parser Mode

630385A0 0000000024 63038540 630385E4 001  -------- -------- 6072882C  Parser Mode Q1

630385E4 0000000024 630385A0 63038628 001  -------- -------- 60728850  Parser Mode Q2

63038628 0000002000 630385E4 63038E24 001  -------- -------- 607DC4FC  Reg Function 1

63038E24 0000000052 63038628 63038E84 001  -------- -------- 607287BC  Parser Mode

63038E84 0000000024 63038E24 63038EC8 001  -------- -------- 6072882C  Parser Mode Q1

63038EC8 0000000024 63038E84 63038F0C 001  -------- -------- 60728850  Parser Mode Q2

63038F0C 0000000144 63038EC8 63038FC8 001  -------- -------- 60EE29BC  Entity MIB API

63038FC8 0000000108 63038F0C 63039060 001  -------- -------- 61A520D0  TTY Background

 --More--

         I/O memory

 Address      Bytes     Prev     Next Ref     PrevF    NextF Alloc PC  what

0F000000 0000000044 00000000 0F000058 000  62A4D018 0        00000000  (fragment)

0F000058 0000000276 0F000000 0F000198 001  -------- -------- 6075C440  *Packet Data*

0F000198 0000000276 0F000058 0F0002D8 001  -------- -------- 6075C440  *Packet Data*

0F0002D8 0000000276 0F000198 0F000418 001  -------- -------- 6075C440  *Packet Data*

0F000418 0000000276 0F0002D8 0F000558 001  -------- -------- 6075C440  *Packet Data*

0F000558 0000000276 0F000418 0F000698 001  -------- -------- 6075C440  *Packet Data*

0F000698 0000000276 0F000558 0F0007D8 001  -------- -------- 6075C440  *Packet Data*

0F0007D8 0000000276 0F000698 0F000918 001  -------- -------- 6075C440  *Packet Data*

0F000918 0000000276 0F0007D8 0F000A58 001  -------- -------- 6075C440  *Packet Data*

 --More--


Описание полей из примера 1.6.

Можно использовать модификацию команды show memory free для отображения свободных блоков в каждом пуле памяти (пример 1.7). Вывод команды содержит перечень свободных блоков в порядке списков свободных блоков. Пустые списки свободных блоков отображаются без последующей информации о блоках памяти.

Менеджер фрагментов

    Менеджер пулов предоставляет довольно эффективный способ организации блоков памяти разного размера. Однако это не дается даром: для каждого такого блока памяти приходится использовать 32 байта служебной информации. Конечно, для пулов с небольшим количеством блоков большого размера на служебную информацию тратится весьма малый объем памяти. Однако для пулов, содержащих несколько тысяч маленьких блоков, такая расточительность менеджера пулов становится неоправданной. Как вариант решения возникшей проблемы, ядро предоставляет так называемый менеджер фрагментов (chunk manager), который обслуживает большие пулы с большим количеством маленьких блоков. При этом память не расходуется на служебную информацию для каждого блока.

    В отличие от менеджера пулов памяти, менеджер фрагментов не оперирует со списками свободных блоков. Вместо этого он разбивает большой блок памяти, выделенный из одного из пулов, на множество фрагментов одинакового размера. В некотором роде работа менеджера фрагментов аналогична работе менеджера пулов, только все операции с фрагментами выполняются в пределах одного пула.

    В общем случае механизм работы с памятью выглядит следующим образом: процесс запрашивает выделение большого блока памяти из определенного пула. Затем процесс обращается к менеджеру фрагментов для разделения этого блока на несколько фрагментов фиксированного размера и последующего выделения отдельных фрагментов. Преимущество такого подхода состоит в том, что служебная информация (32 байта) связана с большим блоком памяти, а менеджеру пулов не приходится выделять множество маленьких кусочков памяти. Таким образом, удается заметно снизить фрагментацию пула памяти.

Использование памяти процессами

    Модификация команды show process — show process memory — позволяет получить информацию об использовании памяти отдельными процессами. Данная команда поможет быстро определить доступный объем памяти и объем памяти, занятой процессами. 

Результат выполнения команды show process memory приведен в примере 1.8.

Первая строка вывода команды в примере 1.8 отображает суммарный объем памяти в пулах, объем свободной и занятой памяти. Данные из первой строки вывода соответствуют статистике для процессорного пула памяти (processor memory pool) и совпадают с выводом команды show memory.    Далее вывод команды содержит детальную информацию об использовании памяти каждым процессом, которая рассмотрена более подробно ниже.

 Следует обратить внимание на процессы, помеченные как *Init*, *Sched* и *Dead*. На самом деле это вовсе не процессы, а информация, соответствующая им, которая описывает выделенную память за пределами реальных процессов. Приведенные ниже сведения подробно описывают данную информацию.

Проблемы, связанные с выделением памяти

    Во всех примерах, рассмотренных выше, мы предполагали, что запрос процесса на выделение памяти всегда обслуживается и память процессу выделяется. Однако это не всегда так. Ресурсы памяти, как и ресурсы центрального процессора, ограничены, поэтому всегда есть вероятность нехватки требуемого объема памяти. Что же происходит в случае отказа подобного рода?  В зависимости от того, для чего необходима выделяемая память, процесс может либо продолжать выполняться, либо остановиться и прекратить работу. В любом случае при получении запроса, который менеджер пулов не в состоянии обработать, он выводит предупреждающее сообщение на консоль:

%SYS-2-MALLOCFAIL: Memro allocation of 2129940 bytes failed from 0x6024C00C,

pool I/O, aligment 32 -Process= "OIR Handler", ipl= 4, pid= 7

-Traceback= 6024E738 6024FDA0 6024C014 602329C8 60232A40 6025A6C8 60CEA748

60CDD700 60CDF5F8 60CDF6E8 60CDCB40 60286F1C 602951

Существуют две причины, по которым запрос на выделение памяти не отрабатывается:

Обычно отказы из-за нехватки памяти возникают тогда, когда физически не установлена память для поддержания всех возможностей системы. Существует два варианта решения указанной проблемы: увеличение объема памяти маршрутизатора либо уменьшение затрат ресурсов памяти (уменьшение количества интерфейсов и различных программных возможностей системы). В редких случаях ошибка нехватки памяти может быть связана с утечкой памяти (memory leak) в одном из процессов. Это означает, что процесс постоянно пытается выделить память, однако никогда ее не освобождает, что обычно приводит к расходу всей доступной памяти. Обычно утечки памяти связаны с ошибками в программном обеспечении.

Сбои выделения памяти могут также происходить при наличии требуемого объема свободной памяти. Например, рассмотрим вывод команды show memory (пример 1.9.)

В рассматриваемом примере в системе доступно 20960428 байт свободной памяти. Однако, если попытаться выделить 9000 байт памяти, возникнет ошибка. Чтобы понять, почему так происходит, достаточно взглянуть на значение в колонке Largest. Поскольку на момент выполнения команды show memory максимальный непрерывный блок памяти составляет 8426 байт, выделить 9000 байт нам никак не удастся.

Ход событий подобного рода ярко демонстрирует неблагоприятные последствия фрагментации памяти. Память фрагментируется при выделении большого количества блоков маленького размера, которые затем освобождаются таким образом, что менеджеру пулов не удается объединить их в блоки большего размера. Таким образом, когда все большие блоки памяти окажутся разделенными на маленькие фрагменты, начинают проявляться ошибки выделения памяти, связанные с ее фрагментацией.

    Менеджер пулов спроектирован таким образом, чтобы избегать нежелательной фрагментации памяти, и в большинстве случаев он с этим успешно справляется. Однако в некоторых случаях механизм устранения фрагментации не срабатывает (как в рассмотренном ранее примере).

Менеджер пакетного буфера

    Маршрутизируя пакеты, система должна иметь некоторое пространство памяти для временного хранения пакетов. Обычно для этого создаются буферы памяти, в которых хранятся поступающие пакеты, пока система решает, куда их переправить. 

    Поскольку вся идея операционной системы IOS заключается в маршрутизации пакетов, для работы с буфером пакетов существует специальный менеджер пакетного буфера (packet buffer manager). Он используется системой для создания и последующего управления набором пулов буфера пакетов.    Буферы в таких пулах памяти имеют общее название — системные буферы.

    Менеджер буферного пула предоставляет удобный способ манипуляции набором (или пулом) буферов определенного размера. Несмотря на то что менеджер буферного пула может использоваться для управления любым видом буферных пулов, преимущественно он применяется для манипуляции с буфером пакетов.

    Пулы памяти для буферизации пакетов создаются путем выделения памяти из пула (например, процессорного или пула ввода-вывода). Для того чтобы создать пул, менеджер пакетного буфера требует у менеджера пулов выделить блок памяти и затем разделяет его на буферы. Менеджер пакетного буфера создает список всех свободных буферов для их последующего заполнения и освобождения.

    Пулы пакетного буфера могут быть либо статическими, либо динамическими. Статический пул создается с фиксированным количеством буферов, т.е. далее по ходу работы дополнительные буферы не выделяются. Динамические пулы создаются с минимальным количеством буферов (так называемые постоянные буферы) с возможностью дальнейшего создания и удаления дополнительных буферов. При необходимости расширения динамического пула буферов менеджер пулов старается немедленно удовлетворить запрос на расширение. Если же немедленно расширить пул не удается, запрос на расширение обрабатывается позднее фоновым процессом менеджера пулов.

    Пулы пакетного буфера могут быть общими либо локальными. 

Системные буферы

    В любой IOS-системе существует определенный набор общих буферных пулов — системных буферов. Эти буферные пулы используются для коммутации приходящих пакетов либо для хранения пакетов, генерируемых системой (например, тестрвые пакеты сетевых интерфейсов или пакеты обновления таблиц маршрутизации). Информация, касающаяся системных и прочих буферов, может быть получена с помощью команды show buffer (пример 1.10).

Указанные в примере общие буферы являются стандартными для любой системы IOS. У каждого буфера есть имя (как, например, small buffer, или малый буфер, middle buffer, или средний буфер, и т.д.), которое указывает на определенный пул. За названием пула следует размер буферов, содержащихся в данном пуле. В пределах одного пула размер всех буферов одинаковый и варьируется от 104 до 18024 байт, чтобы приспосабливаться к передаваемым настройке параметра размера передаваемого блока (maximum transmission unit — MTU), сопоставленных различным сетевым интерфейсам. Содержимое прочих полей вывода содержит информацию, которая описана ниже.

  

запрос на выделение буфера получен во время отработки прерывания, когда расширение пула невозможно;

     получен запрос на выделение буфера, в то время как доступных буферов не осталось, а объем  свободной памяти не позволяет расширить пул.

  Чтобы понять работу менеджера пакетных буферов, рассмотрим коммутацию пакетов и проследим изменения в выводе команды show buffers для определенного пула. Начнем с рассмотрения списка из 16-та свободных буферов, которые приведены в примере ниже.

 Предположим, что система получила восемь сетевых пакетов, которые могут быть размешены в 104-байтовых буферах. В результате восемь пакетов размешаются в восьми буферах, а список свободных буферов сокращается до восьми (рис. 1.8).

Если система получает еше четыре пакета до того, как были обработаны предыдущие восемь, то количество свободных буферов сокращается до четырех (рис. 1.9):

Small buffers, 104 bytes (total 16, permanent 16):

4 in free list (8 min, 16 max allowed)

12 hits, 4 misses, 0 trims, 0 created 0 failures (0 no memory)

Итак, свободных буферов — четыре, использованных — двенадцать. Поскольку минимальное значение свободных буферов составляет восемь (8 min), мы имеем четыре “промаха” (4 misses). Это говорит менеджеру о необходимости расширить пул буферов, чтобы число свободных буферов составляло минимально допустимое (т.е. восемь в нашем примере). На рис. 1.10 показан процесс расширения пула буферов:

Small buffers, 104 bytes (total 20, permanent 16):

8 in free list (8 min, 16 max allowed)

12 hits, 4 misses, 0 trims, 4 created 0 failures (0 no memory)

Из примера видно, что менеджер создал четыре дополнительных буфера (4 created) для того, чтобы число свободных буферов достигало минимально допустимое значение — 8 (8 min).

Теперь представим, что требуется выделить девять буферов для размещения пакетов, а уже использованные буферы по-прежнему не освобождены (данная ситуация проиллюстрирована  на рис. 1.11).

 Из вывода команды show buffers следует, что список свободных буферов оказался полностью исчерпанным. В результате свободных буферов в пуле не осталось (0 in free list), 20 буферов заполнено (20 hits), есть 13 промахов и один отказ (так как один пакет не удалось разместить в буфере).

Small buffers, 104 bytes (total 20, permanent 16):

0 if free list (8 min, 16 max allowed)

20 hits, 13 misses, 0 trims, 4 created

1 failure (0 no memory)

В итоге система обрабатывает поступившие пакеты и освобождает ранее занятые буферы. Пусть система IOS обработала 17 пакетов из 20-ти, и в результате было освобождено 17 буферов, как показано на рис. 1.12,

Small buffers, 104 bytes (total 20, permanent 16):

17 in free list (8 min, 16 max allowed)

20 hits, 13 misses, 0 trims, 4 created 1 failure (0 no memory)

Итак, рассматриваемый нами пул содержит теперь 17 свободных буферов. Однако, как показывает значение шах allowed, максимально возможное число свободных буферов составляет 16. Это говорит менеджеру о необходимости сократить размер свободной области до 16-ти буферов. В итоге один буфер высвобождается из пула (1 trims), как показано на рис. 1.13.

Small buffers, 104 bytes (total 20, permanent 16):

17 in free list (8 min, 16 max allowed)

20 hits, 13 misses, 1 trims, 4 created 1 failure (0 no memory)

    В результате обработки всех пакетов операционная система IOS освобождает занятые буферы, а менеджер пула сокращает число свободных буферов до максимально допустимого значения, как показано в примере ниже.

Small buffers, 104 bytes (total 16, permanent 16):

16 in free list (8 min, 16 max allowed)

20 hits, 13 misses, 4 trims, 4 created 1 failure (0 no memory)

Драйверы устройств

    Система IOS содержит драйверы для различных устройств, в частности карты флэш-памяти, памяти NVRAM и установленных в системе сетевых устройств.

Драйверы сетевых устройств операционной системы IOS предоставляют интерфейс для работы с входящими и исходящими пакетами. Любой драйвер состоит из двух компонентов: управляющей части и компонента, связанного с хранением и обработкой данных. Управляющая часть драйвера служит для контроля за состоянием устройства (например, отключение интерфейса). Компонент данных отвечает за передачу информации через устройство и поддерживает операции коммутации пакетов, драйверы сетевых устройств тесно связаны с механизмом коммутации пакетов.

    Драйверы устройств взаимодействуют с другими частями системы IOS посредством специальной управляющей структуры, называемой дескриптором интерфейса (interface descriptor block — IDB). Данная структура содержит список управляющих функций драйвера и информацию о параметрах устройства и его состоянии (например, IP-адрес, статистику прохождения сетевых пакетов). Операционная система IOS содержит дескрипторы для каждого интерфейса.

    Процесс эволюции межсетевой операционной системы IOS начинался с маленькой системы, превратившейся со временем в очень мощную сетевую платформу. Основные элементы IOS не отличаются от элементов других операционных систем. Однако все компоненты операционной системы IOS оптимизированы для эффективной работы в условиях ограниченного объема памяти и необходимости быстрой коммутации пакетов.

    IOS использует механизмы кооперативной многозадачности и линейной адресации памяти. Все программы, буферы и таблицы маршрутизации размешаются в пределах одного адресного пространства, соответственно любой процесс имеет доступ к памяти любого другого процесса.    Процессы в системе IOS эквивалентны потокам в других операционных системах.

    Система IOS содержит маленькое ядро, которое планирует выполнение процессов процессором. В отличие от других операционных систем, ядро системы IOS выполняется на пользовательском уровне (не используется механизм защищенного режима) и разделяет одно и то же пространство адресов памяти со всеми процессами.

    Драйверы устройств операционной системы IOS предоставляют логическую абстракцию аппаратной части маршрутизатора от его программного обеспечения. Драйверы сетевых устройств очень тесно связаны с работой механизма коммутации пакетов.